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
- #deleteWebhook(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.
- #sendBroadcast(id, body) ⇒ Object
- #setWebhook(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
426 427 428 |
# File 'lib/mailkite.rb', line 426 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.
292 293 294 |
# File 'lib/mailkite.rb', line 292 def agent() request("POST", "/v1/agent", ) end |
#checkDomainAvailability(domain) ⇒ Object
339 340 341 |
# File 'lib/mailkite.rb', line 339 def checkDomainAvailability(domain) request("GET", "/api/domains/register/check?domain=#{CGI.escape(domain)}") end |
#createBroadcast(body) ⇒ Object
439 440 441 |
# File 'lib/mailkite.rb', line 439 def createBroadcast(body) request("POST", "/api/broadcasts", body) end |
#createDomain(body) ⇒ Object
307 308 309 |
# File 'lib/mailkite.rb', line 307 def createDomain(body) request("POST", "/api/domains", body) end |
#createList(body) ⇒ Object
401 402 403 |
# File 'lib/mailkite.rb', line 401 def createList(body) request("POST", "/api/lists", body) end |
#createRoute(body) ⇒ Object
352 353 354 |
# File 'lib/mailkite.rb', line 352 def createRoute(body) request("POST", "/api/routes", body) end |
#createTemplate(body) ⇒ Object
373 374 375 |
# File 'lib/mailkite.rb', line 373 def createTemplate(body) request("POST", "/api/templates", body) end |
#decrypt(envelope, private_key) ⇒ Object
494 495 496 |
# File 'lib/mailkite.rb', line 494 def decrypt(envelope, private_key) Mailkite.decrypt(envelope, private_key) end |
#deleteBroadcast(id) ⇒ Object
451 452 453 |
# File 'lib/mailkite.rb', line 451 def deleteBroadcast(id) request("DELETE", "/api/broadcasts/#{id}") end |
#deleteDomain(id) ⇒ Object
319 320 321 |
# File 'lib/mailkite.rb', line 319 def deleteDomain(id) request("DELETE", "/api/domains/#{id}") end |
#deleteList(id) ⇒ Object
413 414 415 |
# File 'lib/mailkite.rb', line 413 def deleteList(id) request("DELETE", "/api/lists/#{id}") end |
#deleteRoute(id) ⇒ Object
356 357 358 |
# File 'lib/mailkite.rb', line 356 def deleteRoute(id) request("DELETE", "/api/routes/#{id}") end |
#deleteWebhook(id) ⇒ Object
331 332 333 |
# File 'lib/mailkite.rb', line 331 def deleteWebhook(id) request("DELETE", "/api/domains/#{id}/webhook") end |
#encrypt(plaintext, public_key) ⇒ Object
490 491 492 |
# File 'lib/mailkite.rb', line 490 def encrypt(plaintext, public_key) Mailkite.encrypt(plaintext, public_key) end |
#getBroadcast(id) ⇒ Object
443 444 445 |
# File 'lib/mailkite.rb', line 443 def getBroadcast(id) request("GET", "/api/broadcasts/#{id}") end |
#getDomain(id) ⇒ Object
311 312 313 |
# File 'lib/mailkite.rb', line 311 def getDomain(id) request("GET", "/api/domains/#{id}") end |
#getList(id) ⇒ Object
405 406 407 |
# File 'lib/mailkite.rb', line 405 def getList(id) request("GET", "/api/lists/#{id}") end |
#getMessage(id) ⇒ Object
388 389 390 |
# File 'lib/mailkite.rb', line 388 def getMessage(id) request("GET", "/api/messages/#{id}") end |
#getTemplate(id) ⇒ Object
369 370 371 |
# File 'lib/mailkite.rb', line 369 def getTemplate(id) request("GET", "/api/templates/#{id}") end |
#getWebhookSecret(id) ⇒ Object
315 316 317 |
# File 'lib/mailkite.rb', line 315 def getWebhookSecret(id) request("GET", "/api/domains/#{id}/webhook/secret") end |
#listBaseTemplates ⇒ Object
365 366 367 |
# File 'lib/mailkite.rb', line 365 def listBaseTemplates request("GET", "/api/templates/base") end |
#listBroadcasts ⇒ Object
--- Broadcasts -----------------------------------------------------
435 436 437 |
# File 'lib/mailkite.rb', line 435 def listBroadcasts request("GET", "/api/broadcasts") end |
#listDomains ⇒ Object
--- Domains --------------------------------------------------------
303 304 305 |
# File 'lib/mailkite.rb', line 303 def listDomains request("GET", "/api/domains") end |
#listListContacts(id, before = nil, limit = nil) ⇒ Object
417 418 419 420 421 422 423 424 |
# File 'lib/mailkite.rb', line 417 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 ----------------------------------------------------------
397 398 399 |
# File 'lib/mailkite.rb', line 397 def listLists request("GET", "/api/lists") end |
#listMessages(before = nil, limit = nil, search = nil) ⇒ Object
--- Messages & deliveries -----------------------------------------
378 379 380 381 382 383 384 385 386 |
# File 'lib/mailkite.rb', line 378 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 ---------------------------------------------------------
348 349 350 |
# File 'lib/mailkite.rb', line 348 def listRoutes request("GET", "/api/routes") end |
#listTemplates ⇒ Object
--- Templates ------------------------------------------------------
361 362 363 |
# File 'lib/mailkite.rb', line 361 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
343 344 345 |
# File 'lib/mailkite.rb', line 343 def registerDomain(body) request("POST", "/api/domains/register", body) end |
#removeListContact(id, contactId) ⇒ Object
430 431 432 |
# File 'lib/mailkite.rb', line 430 def removeListContact(id, contactId) request("DELETE", "/api/lists/#{id}/contacts/#{contactId}") end |
#reply_block_sender ⇒ Object
486 487 488 |
# File 'lib/mailkite.rb', line 486 def reply_block_sender Mailkite.reply_block_sender end |
#reply_drop ⇒ Object
482 483 484 |
# File 'lib/mailkite.rb', line 482 def reply_drop Mailkite.reply_drop end |
#reply_ok ⇒ Object
Instance wrappers around the module-level crypto helpers. No network call.
474 475 476 |
# File 'lib/mailkite.rb', line 474 def reply_ok Mailkite.reply_ok end |
#reply_spam ⇒ Object
478 479 480 |
# File 'lib/mailkite.rb', line 478 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
392 393 394 |
# File 'lib/mailkite.rb', line 392 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.
298 299 300 |
# File 'lib/mailkite.rb', line 298 def route() request("POST", "/v1/route", ) end |
#semanticSearch(query) ⇒ Object
--- Docs ----------------------------------------------------------- Semantic search over the MailKite docs. PUBLIC — no auth required. Returns { "query" => ..., "matches" => [...] }.
462 463 464 |
# File 'lib/mailkite.rb', line 462 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.
217 218 219 |
# File 'lib/mailkite.rb', line 217 def send() request("POST", "/v1/send", ) end |
#sendBroadcast(id, body) ⇒ Object
455 456 457 |
# File 'lib/mailkite.rb', line 455 def sendBroadcast(id, body) request("POST", "/api/broadcasts/#{id}/send", body) end |
#setWebhook(id, body) ⇒ Object
327 328 329 |
# File 'lib/mailkite.rb', line 327 def setWebhook(id, body) request("PUT", "/api/domains/#{id}/webhook", body) end |
#testWebhook(id) ⇒ Object
335 336 337 |
# File 'lib/mailkite.rb', line 335 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
447 448 449 |
# File 'lib/mailkite.rb', line 447 def updateBroadcast(id, body) request("PATCH", "/api/broadcasts/#{id}", body) end |
#updateList(id, body) ⇒ Object
409 410 411 |
# File 'lib/mailkite.rb', line 409 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.
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'lib/mailkite.rb', line 253 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
323 324 325 |
# File 'lib/mailkite.rb', line 323 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.
469 470 471 |
# File 'lib/mailkite.rb', line 469 def verifyWebhook(signature, payload, secret, tolerance_ms = DEFAULT_TOLERANCE_MS) Mailkite.verify_webhook(signature, payload, secret, tolerance_ms) end |