mailkite 0.5.0 → 0.6.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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mailkite.rb +88 -6
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16ccb6cd1fe7bcc80237e945bd42ea0f5f0f69d6fc618b955d8b0e93f70c04ef
4
- data.tar.gz: 198dd419d07e5dda9fb2023ec653b600098f63f6837f11344db3e156d28c37e3
3
+ metadata.gz: 79f557c742e7377043c6fbbfc62c788bde380e6c75f647a354c4182346275a4d
4
+ data.tar.gz: be02421caccae364a81433fd239d043e19aeb546817c0acbf3c9727850894785
5
5
  SHA512:
6
- metadata.gz: d61fd1fe911b68d90fb8359eb62fca139a8858d8dd3752d4930420e6ea2fdb6ed59c9264936a3582359ae407d5320946621c7ddcca151e691aeb24a6bf8977a5
7
- data.tar.gz: 88ff488ba25e4ffccf1fdc4c26b5bcaf38b2a7bf7fb3d795a0f8165c08f53e6166bcb01420ec826c370895b163b83cd427ae7e984c1b97f4953eece037499d69
6
+ metadata.gz: 94b4ec4ac99c756f5887d9f5526ac931df163675e0dcd7a460a9703847b253a5c2852d744f227704f847791bb183f6a1226178ee0714b26eb6fc4249d68a3e17
7
+ data.tar.gz: 501cce3bfee6edd4123a24f337325668e2a4009523814b5d3989fa197a4d4fc2185587dfd3bdf694f2ceed3ba0330e14ceeeac54f351f4f8e30c91b4310c7a97
data/lib/mailkite.rb CHANGED
@@ -15,7 +15,7 @@ require "base64"
15
15
  require "cgi"
16
16
 
17
17
  module Mailkite
18
- VERSION = "0.5.0"
18
+ VERSION = "0.6.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
@@ -165,6 +165,27 @@ module Mailkite
165
165
  req.body = JSON.generate(body)
166
166
  end
167
167
 
168
+ perform(req, uri)
169
+ end
170
+
171
+ # Raw-binary request used by uploadAttachment for `bytes`/`path` uploads:
172
+ # the body is the file bytes themselves (not JSON, not multipart) and the
173
+ # Content-Type names the file's media type. Same auth + response parsing.
174
+ def request_binary(bytes, filename:, content_type:, retention_days: nil)
175
+ query = { "filename" => filename }
176
+ query["retentionDays"] = retention_days unless retention_days.nil?
177
+ qs = query.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v.to_s)}" }.join("&")
178
+ uri = URI("#{@base_url}/v1/attachments?#{qs}")
179
+ req = Net::HTTP::Post.new(uri)
180
+ req["Authorization"] = "Bearer #{@api_key}"
181
+ req["Content-Type"] = content_type
182
+ req.body = bytes
183
+ perform(req, uri)
184
+ end
185
+
186
+ # Send a prepared Net::HTTP request and parse the JSON response (shared by
187
+ # `request` and `request_binary`).
188
+ def perform(req, uri)
168
189
  res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(req) }
169
190
  text = res.body
170
191
  data = text && !text.empty? ? JSON.parse(text) : nil
@@ -184,12 +205,73 @@ module Mailkite
184
205
  request("POST", "/v1/send", message)
185
206
  end
186
207
 
187
- # Upload a file (base64 `content`) and get back a secure, time-limited URL to
188
- # reference as a send() attachment ({ filename, url }) or link inline —
189
- # instead of base64-inlining large files on every send. `file` keys:
190
- # filename, content (base64), plus optional contentType and retentionDays.
208
+ # Extension MIME map for raw-binary attachment uploads (default
209
+ # application/octet-stream when an extension is unknown).
210
+ ATTACHMENT_MIME = {
211
+ "pdf" => "application/pdf",
212
+ "png" => "image/png",
213
+ "jpg" => "image/jpeg",
214
+ "jpeg" => "image/jpeg",
215
+ "gif" => "image/gif",
216
+ "webp" => "image/webp",
217
+ "svg" => "image/svg+xml",
218
+ "csv" => "text/csv",
219
+ "txt" => "text/plain",
220
+ "html" => "text/html",
221
+ "json" => "application/json",
222
+ "zip" => "application/zip",
223
+ "doc" => "application/msword",
224
+ "docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
225
+ "xls" => "application/vnd.ms-excel",
226
+ "xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
227
+ "ics" => "text/calendar",
228
+ "ical" => "text/calendar",
229
+ }.freeze
230
+
231
+ # Upload a file and get back a secure, time-limited URL to reference as a
232
+ # send() attachment ({ filename, url }) or link inline — instead of
233
+ # base64-inlining large files on every send. Provide the file ONE of four
234
+ # ways via the `file` hash (priority order):
235
+ # 1. url — MailKite fetches & re-hosts the remote file
236
+ # 2. bytes — raw binary string, uploaded directly
237
+ # 3. path — local file read off disk, then uploaded as bytes
238
+ # 4. content — base64 string (the original behavior)
239
+ # Plus optional filename, contentType, and retentionDays.
191
240
  def uploadAttachment(file)
192
- request("POST", "/v1/attachments", file)
241
+ url = file["url"] || file[:url]
242
+ bytes = file["bytes"] || file[:bytes]
243
+ path = file["path"] || file[:path]
244
+ content = file["content"] || file[:content]
245
+ filename = file["filename"] || file[:filename]
246
+ content_type = file["contentType"] || file[:contentType]
247
+ retention_days = file["retentionDays"] || file[:retentionDays]
248
+
249
+ if url
250
+ body = { "url" => url }
251
+ body["filename"] = filename unless filename.nil?
252
+ body["contentType"] = content_type unless content_type.nil?
253
+ body["retentionDays"] = retention_days unless retention_days.nil?
254
+ return request("POST", "/v1/attachments", body)
255
+ end
256
+
257
+ if bytes || path
258
+ if path
259
+ bytes = File.binread(path)
260
+ filename ||= File.basename(path)
261
+ content_type ||= ATTACHMENT_MIME[File.extname(path).downcase.delete_prefix(".")]
262
+ end
263
+ content_type ||= "application/octet-stream"
264
+ return request_binary(bytes, filename: filename, content_type: content_type, retention_days: retention_days)
265
+ end
266
+
267
+ if content
268
+ body = { "content" => content, "filename" => filename }
269
+ body["contentType"] = content_type unless content_type.nil?
270
+ body["retentionDays"] = retention_days unless retention_days.nil?
271
+ return request("POST", "/v1/attachments", body)
272
+ end
273
+
274
+ raise ArgumentError, "uploadAttachment requires one of: path, bytes, url, or content"
193
275
  end
194
276
 
195
277
  # Run an inbound message through an AI agent. message keys: text (required),
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailkite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - MailKite