Class: Mailkite::Client
- Inherits:
-
Object
- Object
- Mailkite::Client
- Defined in:
- lib/mailkite.rb
Constant Summary collapse
- VERBS =
{ "GET" => Net::HTTP::Get, "POST" => Net::HTTP::Post, "PUT" => Net::HTTP::Put, "PATCH" => Net::HTTP::Patch, "DELETE" => Net::HTTP::Delete, }.freeze
- ATTACHMENT_MIME =
Extension → MIME map for raw-binary attachment uploads (default application/octet-stream when an extension is unknown).
{ "pdf" => "application/pdf", "png" => "image/png", "jpg" => "image/jpeg", "jpeg" => "image/jpeg", "gif" => "image/gif", "webp" => "image/webp", "svg" => "image/svg+xml", "csv" => "text/csv", "txt" => "text/plain", "html" => "text/html", "json" => "application/json", "zip" => "application/zip", "doc" => "application/msword", "docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "xls" => "application/vnd.ms-excel", "xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "ics" => "text/calendar", "ical" => "text/calendar", }.freeze
Instance Method Summary collapse
- #addListContacts(id, body) ⇒ Object
-
#agent(message) ⇒ Object
Run an inbound message through an AI agent.
- #checkDomainAvailability(domain) ⇒ Object
- #createBroadcast(body) ⇒ Object
- #createDomain(body) ⇒ Object
- #createList(body) ⇒ Object
- #createRoute(body) ⇒ Object
- #createTemplate(body) ⇒ Object
- #decrypt(envelope, private_key) ⇒ Object
- #deleteBroadcast(id) ⇒ Object
- #deleteDomain(id) ⇒ Object
- #deleteList(id) ⇒ Object
- #deleteRoute(id) ⇒ Object
- #deleteTrackingWebhook(id) ⇒ Object
- #deleteWebhook(id) ⇒ Object
- #deleteWebhookEvents(id) ⇒ Object
- #encrypt(plaintext, public_key) ⇒ Object
- #getBroadcast(id) ⇒ Object
- #getDomain(id) ⇒ Object
- #getList(id) ⇒ Object
- #getMessage(id) ⇒ Object
- #getTemplate(id) ⇒ Object
- #getWebhookSecret(id) ⇒ Object
-
#initialize(api_key = nil, base_url = DEFAULT_BASE_URL, access_token: nil, get_token: nil) ⇒ Client
constructor
Authenticate with a Bearer token.
- #listBaseTemplates ⇒ Object
-
#listBroadcasts ⇒ Object
--- Broadcasts -----------------------------------------------------.
-
#listDomains ⇒ Object
--- Domains --------------------------------------------------------.
- #listListContacts(id, before = nil, limit = nil) ⇒ Object
-
#listLists ⇒ Object
--- Lists ----------------------------------------------------------.
-
#listMessages(before = nil, limit = nil, search = nil) ⇒ Object
--- Messages & deliveries -----------------------------------------.
-
#listRoutes ⇒ Object
--- Routes ---------------------------------------------------------.
-
#listTemplates ⇒ Object
--- Templates ------------------------------------------------------.
-
#perform(req, uri) ⇒ Object
Send a prepared Net::HTTP request and parse the JSON response (shared by
requestandrequest_binary). - #registerDomain(body) ⇒ Object
- #removeListContact(id, contactId) ⇒ Object
- #reply_block_sender ⇒ Object
- #reply_drop ⇒ Object
-
#reply_ok ⇒ Object
Instance wrappers around the module-level crypto helpers.
- #reply_spam ⇒ Object
-
#request(method, path, body = nil) ⇒ Object
Low-level request.
-
#request_binary(bytes, filename:, content_type:, retention_days: nil) ⇒ Object
Raw-binary request used by uploadAttachment for
bytes/pathuploads: the body is the file bytes themselves (not JSON, not multipart) and the Content-Type names the file's media type. - #retryDelivery(id) ⇒ Object
-
#route(message) ⇒ Object
Route an inbound message to its configured destination.
-
#semanticSearch(query) ⇒ Object
--- Docs ----------------------------------------------------------- Semantic search over the MailKite docs.
-
#send(message) ⇒ Object
--- Sending -------------------------------------------------------- message keys: from, to, text/html, etc.
-
#sendBatch(batch) ⇒ Object
Send one personalized message per recipient (up to 50) in a single call.
- #sendBroadcast(id, body) ⇒ Object
- #setTrackingWebhook(id, body) ⇒ Object
- #setWebhook(id, body) ⇒ Object
- #setWebhookEvents(id, body) ⇒ Object
- #testWebhook(id) ⇒ Object
-
#token ⇒ Object
The Bearer token for one request: a fresh one from get_token if set, else the static key/token.
- #updateBroadcast(id, body) ⇒ Object
- #updateList(id, body) ⇒ Object
-
#uploadAttachment(file) ⇒ Object
Upload a file and get back a secure, time-limited URL to reference as a send() attachment ({ filename, url }) or link inline — instead of base64-inlining large files on every send.
- #verifyDomain(id) ⇒ Object
-
#verifyWebhook(signature, payload, secret, tolerance_ms = DEFAULT_TOLERANCE_MS) ⇒ Object
--- Webhooks ------------------------------------------------------- Instance wrapper around Mailkite.verify_webhook, so you can verify on an existing client.
Constructor Details
#initialize(api_key = nil, base_url = DEFAULT_BASE_URL, access_token: nil, get_token: nil) ⇒ Client
Authenticate with a Bearer token. api_key (mk_live_…) and the access_token: keyword (an
OAuth access token) are equivalent — both are Bearer credentials. For short-lived OAuth
tokens pass get_token: — a callable invoked before each request for a fresh token (it wins):
MailKite::Client.new("mk_live_...")
MailKite::Client.new(access_token: my_oauth_token)
MailKite::Client.new(get_token: -> { current_session.access_token })
160 161 162 163 164 |
# File 'lib/mailkite.rb', line 160 def initialize(api_key = nil, base_url = DEFAULT_BASE_URL, access_token: nil, get_token: nil) @api_key = api_key.nil? ? access_token : api_key @get_token = get_token @base_url = base_url.sub(%r{/+\z}, "") end |
Instance Method Details
#addListContacts(id, body) ⇒ Object
461 462 463 |
# File 'lib/mailkite.rb', line 461 def addListContacts(id, body) request("POST", "/api/lists/#{id}/contacts", body) end |
#agent(message) ⇒ Object
Run an inbound message through an AI agent. message keys: text (required), plus optional subject/from/html/routeId/address/model.
311 312 313 |
# File 'lib/mailkite.rb', line 311 def agent() request("POST", "/v1/agent", ) end |
#checkDomainAvailability(domain) ⇒ Object
374 375 376 |
# File 'lib/mailkite.rb', line 374 def checkDomainAvailability(domain) request("GET", "/api/domains/register/check?domain=#{CGI.escape(domain)}") end |
#createBroadcast(body) ⇒ Object
474 475 476 |
# File 'lib/mailkite.rb', line 474 def createBroadcast(body) request("POST", "/api/broadcasts", body) end |
#createDomain(body) ⇒ Object
326 327 328 |
# File 'lib/mailkite.rb', line 326 def createDomain(body) request("POST", "/api/domains", body) end |
#createList(body) ⇒ Object
436 437 438 |
# File 'lib/mailkite.rb', line 436 def createList(body) request("POST", "/api/lists", body) end |
#createRoute(body) ⇒ Object
387 388 389 |
# File 'lib/mailkite.rb', line 387 def createRoute(body) request("POST", "/api/routes", body) end |
#createTemplate(body) ⇒ Object
408 409 410 |
# File 'lib/mailkite.rb', line 408 def createTemplate(body) request("POST", "/api/templates", body) end |
#decrypt(envelope, private_key) ⇒ Object
529 530 531 |
# File 'lib/mailkite.rb', line 529 def decrypt(envelope, private_key) Mailkite.decrypt(envelope, private_key) end |
#deleteBroadcast(id) ⇒ Object
486 487 488 |
# File 'lib/mailkite.rb', line 486 def deleteBroadcast(id) request("DELETE", "/api/broadcasts/#{id}") end |
#deleteDomain(id) ⇒ Object
338 339 340 |
# File 'lib/mailkite.rb', line 338 def deleteDomain(id) request("DELETE", "/api/domains/#{id}") end |
#deleteList(id) ⇒ Object
448 449 450 |
# File 'lib/mailkite.rb', line 448 def deleteList(id) request("DELETE", "/api/lists/#{id}") end |
#deleteRoute(id) ⇒ Object
391 392 393 |
# File 'lib/mailkite.rb', line 391 def deleteRoute(id) request("DELETE", "/api/routes/#{id}") end |
#deleteTrackingWebhook(id) ⇒ Object
358 359 360 |
# File 'lib/mailkite.rb', line 358 def deleteTrackingWebhook(id) request("DELETE", "/api/domains/#{id}/tracking-webhook") end |
#deleteWebhook(id) ⇒ Object
350 351 352 |
# File 'lib/mailkite.rb', line 350 def deleteWebhook(id) request("DELETE", "/api/domains/#{id}/webhook") end |
#deleteWebhookEvents(id) ⇒ Object
366 367 368 |
# File 'lib/mailkite.rb', line 366 def deleteWebhookEvents(id) request("DELETE", "/api/domains/#{id}/webhook-events") end |
#encrypt(plaintext, public_key) ⇒ Object
525 526 527 |
# File 'lib/mailkite.rb', line 525 def encrypt(plaintext, public_key) Mailkite.encrypt(plaintext, public_key) end |
#getBroadcast(id) ⇒ Object
478 479 480 |
# File 'lib/mailkite.rb', line 478 def getBroadcast(id) request("GET", "/api/broadcasts/#{id}") end |
#getDomain(id) ⇒ Object
330 331 332 |
# File 'lib/mailkite.rb', line 330 def getDomain(id) request("GET", "/api/domains/#{id}") end |
#getList(id) ⇒ Object
440 441 442 |
# File 'lib/mailkite.rb', line 440 def getList(id) request("GET", "/api/lists/#{id}") end |
#getMessage(id) ⇒ Object
423 424 425 |
# File 'lib/mailkite.rb', line 423 def getMessage(id) request("GET", "/api/messages/#{id}") end |
#getTemplate(id) ⇒ Object
404 405 406 |
# File 'lib/mailkite.rb', line 404 def getTemplate(id) request("GET", "/api/templates/#{id}") end |
#getWebhookSecret(id) ⇒ Object
334 335 336 |
# File 'lib/mailkite.rb', line 334 def getWebhookSecret(id) request("GET", "/api/domains/#{id}/webhook/secret") end |
#listBaseTemplates ⇒ Object
400 401 402 |
# File 'lib/mailkite.rb', line 400 def listBaseTemplates request("GET", "/api/templates/base") end |
#listBroadcasts ⇒ Object
--- Broadcasts -----------------------------------------------------
470 471 472 |
# File 'lib/mailkite.rb', line 470 def listBroadcasts request("GET", "/api/broadcasts") end |
#listDomains ⇒ Object
--- Domains --------------------------------------------------------
322 323 324 |
# File 'lib/mailkite.rb', line 322 def listDomains request("GET", "/api/domains") end |
#listListContacts(id, before = nil, limit = nil) ⇒ Object
452 453 454 455 456 457 458 459 |
# File 'lib/mailkite.rb', line 452 def listListContacts(id, before = nil, limit = nil) params = [] params << "before=#{CGI.escape(before.to_s)}" unless before.nil? params << "limit=#{CGI.escape(limit.to_s)}" unless limit.nil? path = "/api/lists/#{id}/contacts" path += "?#{params.join('&')}" unless params.empty? request("GET", path) end |
#listLists ⇒ Object
--- Lists ----------------------------------------------------------
432 433 434 |
# File 'lib/mailkite.rb', line 432 def listLists request("GET", "/api/lists") end |
#listMessages(before = nil, limit = nil, search = nil) ⇒ Object
--- Messages & deliveries -----------------------------------------
413 414 415 416 417 418 419 420 421 |
# File 'lib/mailkite.rb', line 413 def listMessages(before = nil, limit = nil, search = nil) params = [] params << "before=#{CGI.escape(before.to_s)}" unless before.nil? params << "limit=#{CGI.escape(limit.to_s)}" unless limit.nil? params << "search=#{CGI.escape(search.to_s)}" unless search.nil? path = "/api/messages" path += "?#{params.join('&')}" unless params.empty? request("GET", path) end |
#listRoutes ⇒ Object
--- Routes ---------------------------------------------------------
383 384 385 |
# File 'lib/mailkite.rb', line 383 def listRoutes request("GET", "/api/routes") end |
#listTemplates ⇒ Object
--- Templates ------------------------------------------------------
396 397 398 |
# File 'lib/mailkite.rb', line 396 def listTemplates request("GET", "/api/templates") end |
#perform(req, uri) ⇒ Object
Send a prepared Net::HTTP request and parse the JSON response (shared by
request and request_binary).
201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/mailkite.rb', line 201 def perform(req, uri) res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(req) } text = res.body data = text && !text.empty? ? JSON.parse(text) : nil code = res.code.to_i unless code >= 200 && code < 300 = data.is_a?(Hash) ? data["error"] : nil raise Error.new(code, || res. || "HTTP #{code}", data) end data end |
#registerDomain(body) ⇒ Object
378 379 380 |
# File 'lib/mailkite.rb', line 378 def registerDomain(body) request("POST", "/api/domains/register", body) end |
#removeListContact(id, contactId) ⇒ Object
465 466 467 |
# File 'lib/mailkite.rb', line 465 def removeListContact(id, contactId) request("DELETE", "/api/lists/#{id}/contacts/#{contactId}") end |
#reply_block_sender ⇒ Object
521 522 523 |
# File 'lib/mailkite.rb', line 521 def reply_block_sender Mailkite.reply_block_sender end |
#reply_drop ⇒ Object
517 518 519 |
# File 'lib/mailkite.rb', line 517 def reply_drop Mailkite.reply_drop end |
#reply_ok ⇒ Object
Instance wrappers around the module-level crypto helpers. No network call.
509 510 511 |
# File 'lib/mailkite.rb', line 509 def reply_ok Mailkite.reply_ok end |
#reply_spam ⇒ Object
513 514 515 |
# File 'lib/mailkite.rb', line 513 def reply_spam Mailkite.reply_spam end |
#request(method, path, body = nil) ⇒ Object
Low-level request. Every method below is a one-liner on top of this.
172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/mailkite.rb', line 172 def request(method, path, body = nil) uri = URI(@base_url + path) req = VERBS.fetch(method).new(uri) req["Authorization"] = "Bearer #{token}" unless body.nil? req["Content-Type"] = "application/json" req.body = JSON.generate(body) end perform(req, uri) end |
#request_binary(bytes, filename:, content_type:, retention_days: nil) ⇒ Object
Raw-binary request used by uploadAttachment for bytes/path uploads:
the body is the file bytes themselves (not JSON, not multipart) and the
Content-Type names the file's media type. Same auth + response parsing.
187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/mailkite.rb', line 187 def request_binary(bytes, filename:, content_type:, retention_days: nil) query = { "filename" => filename } query["retentionDays"] = retention_days unless retention_days.nil? qs = query.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v.to_s)}" }.join("&") uri = URI("#{@base_url}/v1/attachments?#{qs}") req = Net::HTTP::Post.new(uri) req["Authorization"] = "Bearer #{token}" req["Content-Type"] = content_type req.body = bytes perform(req, uri) end |
#retryDelivery(id) ⇒ Object
427 428 429 |
# File 'lib/mailkite.rb', line 427 def retryDelivery(id) request("POST", "/api/deliveries/#{id}/retry") end |
#route(message) ⇒ Object
Route an inbound message to its configured destination. message keys: from (required), plus optional routeId/address/subject/text/html.
317 318 319 |
# File 'lib/mailkite.rb', line 317 def route() request("POST", "/v1/route", ) end |
#semanticSearch(query) ⇒ Object
--- Docs ----------------------------------------------------------- Semantic search over the MailKite docs. PUBLIC — no auth required. Returns { "query" => ..., "matches" => [...] }.
497 498 499 |
# File 'lib/mailkite.rb', line 497 def semanticSearch(query) request("GET", "/v1/docs/search?query=#{CGI.escape(query)}") end |
#send(message) ⇒ Object
--- Sending --------------------------------------------------------
message keys: from, to, text/html, etc. subject is optional when a
template supplies it. Pass templateId to render a stored template and
templateData (a hash) to fill its variables.
Send an email. message is a hash with "from", "to" and a body ("text"
and/or "html"). Also accepted: "subject" (optional when a template
supplies it), "cc"/"bcc" (string or array), "replyTo", "inReplyTo"
(thread a reply), "attachments" (array of url|content,
contentType), "headers" (hash of extra raw MIME headers, e.g.
List-Unsubscribe — immediate sends only), and "templateId" +
"templateData" to render a stored template.
224 225 226 |
# File 'lib/mailkite.rb', line 224 def send() request("POST", "/v1/send", ) end |
#sendBatch(batch) ⇒ Object
Send one personalized message per recipient (up to 50) in a single call.
batch is a hash with "from" and "recipients" (array of "templateData", "headers" — exactly one address each). Shared fields
("subject", "html"/"text", "templateId", "templateData", "headers", …)
form the base message; per-recipient "templateData" and "headers" are
merged over the shared ones (the recipient wins). Every message passes
the same gates as send() and gets its own id — the response reports each
recipient's outcome in order, so a batch can partially succeed.
236 237 238 |
# File 'lib/mailkite.rb', line 236 def sendBatch(batch) request("POST", "/v1/send/batch", batch) end |
#sendBroadcast(id, body) ⇒ Object
490 491 492 |
# File 'lib/mailkite.rb', line 490 def sendBroadcast(id, body) request("POST", "/api/broadcasts/#{id}/send", body) end |
#setTrackingWebhook(id, body) ⇒ Object
354 355 356 |
# File 'lib/mailkite.rb', line 354 def setTrackingWebhook(id, body) request("PUT", "/api/domains/#{id}/tracking-webhook", body) end |
#setWebhook(id, body) ⇒ Object
346 347 348 |
# File 'lib/mailkite.rb', line 346 def setWebhook(id, body) request("PUT", "/api/domains/#{id}/webhook", body) end |
#setWebhookEvents(id, body) ⇒ Object
362 363 364 |
# File 'lib/mailkite.rb', line 362 def setWebhookEvents(id, body) request("PUT", "/api/domains/#{id}/webhook-events", body) end |
#testWebhook(id) ⇒ Object
370 371 372 |
# File 'lib/mailkite.rb', line 370 def testWebhook(id) request("POST", "/api/domains/#{id}/webhook/test") end |
#token ⇒ Object
The Bearer token for one request: a fresh one from get_token if set, else the static key/token.
167 168 169 |
# File 'lib/mailkite.rb', line 167 def token @get_token ? @get_token.call : @api_key end |
#updateBroadcast(id, body) ⇒ Object
482 483 484 |
# File 'lib/mailkite.rb', line 482 def updateBroadcast(id, body) request("PATCH", "/api/broadcasts/#{id}", body) end |
#updateList(id, body) ⇒ Object
444 445 446 |
# File 'lib/mailkite.rb', line 444 def updateList(id, body) request("PATCH", "/api/lists/#{id}", body) end |
#uploadAttachment(file) ⇒ Object
Upload a file and get back a secure, time-limited URL to reference as a
send() attachment ({ filename, url }) or link inline — instead of
base64-inlining large files on every send. Provide the file ONE of four
ways via the file hash (priority order):
1. url — MailKite fetches & re-hosts the remote file
2. bytes — raw binary string, uploaded directly
3. path — local file read off disk, then uploaded as bytes
4. content — base64 string (the original behavior)
Plus optional filename, contentType, and retentionDays.
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/mailkite.rb', line 272 def uploadAttachment(file) url = file["url"] || file[:url] bytes = file["bytes"] || file[:bytes] path = file["path"] || file[:path] content = file["content"] || file[:content] filename = file["filename"] || file[:filename] content_type = file["contentType"] || file[:contentType] retention_days = file["retentionDays"] || file[:retentionDays] if url body = { "url" => url } body["filename"] = filename unless filename.nil? body["contentType"] = content_type unless content_type.nil? body["retentionDays"] = retention_days unless retention_days.nil? return request("POST", "/v1/attachments", body) end if bytes || path if path bytes = File.binread(path) filename ||= File.basename(path) content_type ||= ATTACHMENT_MIME[File.extname(path).downcase.delete_prefix(".")] end content_type ||= "application/octet-stream" return request_binary(bytes, filename: filename, content_type: content_type, retention_days: retention_days) end if content body = { "content" => content, "filename" => filename } body["contentType"] = content_type unless content_type.nil? body["retentionDays"] = retention_days unless retention_days.nil? return request("POST", "/v1/attachments", body) end raise ArgumentError, "uploadAttachment requires one of: path, bytes, url, or content" end |
#verifyDomain(id) ⇒ Object
342 343 344 |
# File 'lib/mailkite.rb', line 342 def verifyDomain(id) request("POST", "/api/domains/#{id}/verify") end |
#verifyWebhook(signature, payload, secret, tolerance_ms = DEFAULT_TOLERANCE_MS) ⇒ Object
--- Webhooks ------------------------------------------------------- Instance wrapper around Mailkite.verify_webhook, so you can verify on an existing client. No network call; no API key required.
504 505 506 |
# File 'lib/mailkite.rb', line 504 def verifyWebhook(signature, payload, secret, tolerance_ms = DEFAULT_TOLERANCE_MS) Mailkite.verify_webhook(signature, payload, secret, tolerance_ms) end |