mailkite 0.5.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/mailkite.rb +154 -6
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ea16a5e20d5b4548d304b4c3ddd9a11d8ab600c10084b97128d409f92e99e816
|
|
4
|
+
data.tar.gz: b05b9ccaca0842f125cbe58841ba68b8ef57477feb159eb49498d522e4c1c04e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 322718f1d3f37a5861fb5d9436dba95de176bdff6a560645b695371ca70029d5ca2dd320a5379b1b7513cf767bc9143b04c46ec668761667c7262707f91a3522
|
|
7
|
+
data.tar.gz: '03179b18866ef5ffa56291fef71046e5d3d869f48af530f2ab4d5169ecdd80b55a6d00bd947ad7dc870d66f2656dfd56e7bd86f6e28c749f3cc2c0a79a1f1275'
|
data/lib/mailkite.rb
CHANGED
|
@@ -15,7 +15,7 @@ require "base64"
|
|
|
15
15
|
require "cgi"
|
|
16
16
|
|
|
17
17
|
module Mailkite
|
|
18
|
-
VERSION = "0.
|
|
18
|
+
VERSION = "0.8.0"
|
|
19
19
|
DEFAULT_BASE_URL = "https://api.mailkite.dev"
|
|
20
20
|
# Reject webhook events older than this (ms) to block replays. Pass 0 to disable.
|
|
21
21
|
DEFAULT_TOLERANCE_MS = 5 * 60 * 1000
|
|
@@ -147,6 +147,7 @@ module Mailkite
|
|
|
147
147
|
"GET" => Net::HTTP::Get,
|
|
148
148
|
"POST" => Net::HTTP::Post,
|
|
149
149
|
"PUT" => Net::HTTP::Put,
|
|
150
|
+
"PATCH" => Net::HTTP::Patch,
|
|
150
151
|
"DELETE" => Net::HTTP::Delete,
|
|
151
152
|
}.freeze
|
|
152
153
|
|
|
@@ -165,6 +166,27 @@ module Mailkite
|
|
|
165
166
|
req.body = JSON.generate(body)
|
|
166
167
|
end
|
|
167
168
|
|
|
169
|
+
perform(req, uri)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Raw-binary request used by uploadAttachment for `bytes`/`path` uploads:
|
|
173
|
+
# the body is the file bytes themselves (not JSON, not multipart) and the
|
|
174
|
+
# Content-Type names the file's media type. Same auth + response parsing.
|
|
175
|
+
def request_binary(bytes, filename:, content_type:, retention_days: nil)
|
|
176
|
+
query = { "filename" => filename }
|
|
177
|
+
query["retentionDays"] = retention_days unless retention_days.nil?
|
|
178
|
+
qs = query.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v.to_s)}" }.join("&")
|
|
179
|
+
uri = URI("#{@base_url}/v1/attachments?#{qs}")
|
|
180
|
+
req = Net::HTTP::Post.new(uri)
|
|
181
|
+
req["Authorization"] = "Bearer #{@api_key}"
|
|
182
|
+
req["Content-Type"] = content_type
|
|
183
|
+
req.body = bytes
|
|
184
|
+
perform(req, uri)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Send a prepared Net::HTTP request and parse the JSON response (shared by
|
|
188
|
+
# `request` and `request_binary`).
|
|
189
|
+
def perform(req, uri)
|
|
168
190
|
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(req) }
|
|
169
191
|
text = res.body
|
|
170
192
|
data = text && !text.empty? ? JSON.parse(text) : nil
|
|
@@ -184,12 +206,73 @@ module Mailkite
|
|
|
184
206
|
request("POST", "/v1/send", message)
|
|
185
207
|
end
|
|
186
208
|
|
|
187
|
-
#
|
|
188
|
-
#
|
|
189
|
-
|
|
190
|
-
|
|
209
|
+
# Extension → MIME map for raw-binary attachment uploads (default
|
|
210
|
+
# application/octet-stream when an extension is unknown).
|
|
211
|
+
ATTACHMENT_MIME = {
|
|
212
|
+
"pdf" => "application/pdf",
|
|
213
|
+
"png" => "image/png",
|
|
214
|
+
"jpg" => "image/jpeg",
|
|
215
|
+
"jpeg" => "image/jpeg",
|
|
216
|
+
"gif" => "image/gif",
|
|
217
|
+
"webp" => "image/webp",
|
|
218
|
+
"svg" => "image/svg+xml",
|
|
219
|
+
"csv" => "text/csv",
|
|
220
|
+
"txt" => "text/plain",
|
|
221
|
+
"html" => "text/html",
|
|
222
|
+
"json" => "application/json",
|
|
223
|
+
"zip" => "application/zip",
|
|
224
|
+
"doc" => "application/msword",
|
|
225
|
+
"docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
226
|
+
"xls" => "application/vnd.ms-excel",
|
|
227
|
+
"xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
228
|
+
"ics" => "text/calendar",
|
|
229
|
+
"ical" => "text/calendar",
|
|
230
|
+
}.freeze
|
|
231
|
+
|
|
232
|
+
# Upload a file and get back a secure, time-limited URL to reference as a
|
|
233
|
+
# send() attachment ({ filename, url }) or link inline — instead of
|
|
234
|
+
# base64-inlining large files on every send. Provide the file ONE of four
|
|
235
|
+
# ways via the `file` hash (priority order):
|
|
236
|
+
# 1. url — MailKite fetches & re-hosts the remote file
|
|
237
|
+
# 2. bytes — raw binary string, uploaded directly
|
|
238
|
+
# 3. path — local file read off disk, then uploaded as bytes
|
|
239
|
+
# 4. content — base64 string (the original behavior)
|
|
240
|
+
# Plus optional filename, contentType, and retentionDays.
|
|
191
241
|
def uploadAttachment(file)
|
|
192
|
-
|
|
242
|
+
url = file["url"] || file[:url]
|
|
243
|
+
bytes = file["bytes"] || file[:bytes]
|
|
244
|
+
path = file["path"] || file[:path]
|
|
245
|
+
content = file["content"] || file[:content]
|
|
246
|
+
filename = file["filename"] || file[:filename]
|
|
247
|
+
content_type = file["contentType"] || file[:contentType]
|
|
248
|
+
retention_days = file["retentionDays"] || file[:retentionDays]
|
|
249
|
+
|
|
250
|
+
if url
|
|
251
|
+
body = { "url" => url }
|
|
252
|
+
body["filename"] = filename unless filename.nil?
|
|
253
|
+
body["contentType"] = content_type unless content_type.nil?
|
|
254
|
+
body["retentionDays"] = retention_days unless retention_days.nil?
|
|
255
|
+
return request("POST", "/v1/attachments", body)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
if bytes || path
|
|
259
|
+
if path
|
|
260
|
+
bytes = File.binread(path)
|
|
261
|
+
filename ||= File.basename(path)
|
|
262
|
+
content_type ||= ATTACHMENT_MIME[File.extname(path).downcase.delete_prefix(".")]
|
|
263
|
+
end
|
|
264
|
+
content_type ||= "application/octet-stream"
|
|
265
|
+
return request_binary(bytes, filename: filename, content_type: content_type, retention_days: retention_days)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
if content
|
|
269
|
+
body = { "content" => content, "filename" => filename }
|
|
270
|
+
body["contentType"] = content_type unless content_type.nil?
|
|
271
|
+
body["retentionDays"] = retention_days unless retention_days.nil?
|
|
272
|
+
return request("POST", "/v1/attachments", body)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
raise ArgumentError, "uploadAttachment requires one of: path, bytes, url, or content"
|
|
193
276
|
end
|
|
194
277
|
|
|
195
278
|
# Run an inbound message through an AI agent. message keys: text (required),
|
|
@@ -284,6 +367,71 @@ module Mailkite
|
|
|
284
367
|
request("POST", "/api/deliveries/#{id}/retry")
|
|
285
368
|
end
|
|
286
369
|
|
|
370
|
+
# --- Lists ----------------------------------------------------------
|
|
371
|
+
def listLists
|
|
372
|
+
request("GET", "/api/lists")
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def createList(body)
|
|
376
|
+
request("POST", "/api/lists", body)
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def getList(id)
|
|
380
|
+
request("GET", "/api/lists/#{id}")
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def updateList(id, body)
|
|
384
|
+
request("PATCH", "/api/lists/#{id}", body)
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def deleteList(id)
|
|
388
|
+
request("DELETE", "/api/lists/#{id}")
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
def listListContacts(id)
|
|
392
|
+
request("GET", "/api/lists/#{id}/contacts")
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
def addListContacts(id, body)
|
|
396
|
+
request("POST", "/api/lists/#{id}/contacts", body)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def removeListContact(id, contactId)
|
|
400
|
+
request("DELETE", "/api/lists/#{id}/contacts/#{contactId}")
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
# --- Broadcasts -----------------------------------------------------
|
|
404
|
+
def listBroadcasts
|
|
405
|
+
request("GET", "/api/broadcasts")
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
def createBroadcast(body)
|
|
409
|
+
request("POST", "/api/broadcasts", body)
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def getBroadcast(id)
|
|
413
|
+
request("GET", "/api/broadcasts/#{id}")
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
def updateBroadcast(id, body)
|
|
417
|
+
request("PATCH", "/api/broadcasts/#{id}", body)
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def deleteBroadcast(id)
|
|
421
|
+
request("DELETE", "/api/broadcasts/#{id}")
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
def sendBroadcast(id, body)
|
|
425
|
+
request("POST", "/api/broadcasts/#{id}/send", body)
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# --- Docs -----------------------------------------------------------
|
|
429
|
+
# Semantic search over the MailKite docs. PUBLIC — no auth required.
|
|
430
|
+
# Returns { "query" => ..., "matches" => [...] }.
|
|
431
|
+
def semanticSearch(query)
|
|
432
|
+
request("GET", "/v1/docs/search?query=#{CGI.escape(query)}")
|
|
433
|
+
end
|
|
434
|
+
|
|
287
435
|
# --- Webhooks -------------------------------------------------------
|
|
288
436
|
# Instance wrapper around Mailkite.verify_webhook, so you can verify on an
|
|
289
437
|
# existing client. No network call; no API key required.
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mailkite
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- MailKite
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Send and manage email over your own authenticated domain with MailKite.
|
|
14
14
|
email:
|
|
@@ -21,7 +21,7 @@ homepage: https://mailkite.dev/docs/libraries
|
|
|
21
21
|
licenses:
|
|
22
22
|
- MIT
|
|
23
23
|
metadata:
|
|
24
|
-
source_code_uri: https://github.com/mailkite/mailkite
|
|
24
|
+
source_code_uri: https://github.com/mailkite/mailkite-ruby
|
|
25
25
|
post_install_message:
|
|
26
26
|
rdoc_options: []
|
|
27
27
|
require_paths:
|