mailkite 0.11.0 → 0.12.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6150a49b6aeb81a4a2f47110dca45c08d0369de7492de5f09a93ba962aae6e22
4
- data.tar.gz: 7432bb5749a2e701d4a08cbaf92e0a386853e9953c7b4db4cfb23834f480c96d
3
+ metadata.gz: 26eb50d856d1ba16356a5fc399a84414774dccf715a0dc6291b451030ea27272
4
+ data.tar.gz: 3472e6b74b0772e5c18906fb66e9fd8c39dcb6de194fbf1a78b131086d676d3c
5
5
  SHA512:
6
- metadata.gz: e8651f3331f64a40afca30a2b3191d40deb9a9cf71393e8d9df8a1ae9273ad5d73828dc67b38a3f928d80b063ed32c03e337f418a7df1646eb0806dcbb70862c
7
- data.tar.gz: d8989b2cc0b1581990b0b4c0c1622e65fc89b9acec5ad26e4de734b583354fd777f779072d696d84cf267457e9a415c2b57c470872417c138caec224e6e13272
6
+ metadata.gz: ca926ae3006b0fde3931988b8e1cb62f196831e60bf9e3d77cf5b0b10ba8dd724858ef1428a3decc422787e166e876c471605e04384880c1030e209f6dca5420
7
+ data.tar.gz: ae7bcbefece087b52e9936df73b885a63a4e264b6b05d0b6b362fb086dcc0bd4413df2b5b60c598680120e8e4c2adc7358564e453d7293fb970b4e35feb93e09
@@ -0,0 +1,150 @@
1
+ # Docs: docs/integrations/rails-delivery-method.md
2
+ #
3
+ # ActionMailer / Mail delivery method: deliver Mail::Message objects through
4
+ # the MailKite API (POST /v1/send) instead of SMTP.
5
+ #
6
+ # # Rails — the Railtie registers :mailkite automatically:
7
+ # config.action_mailer.delivery_method = :mailkite
8
+ # config.action_mailer.mailkite_settings = { api_key: ENV["MAILKITE_API_KEY"] }
9
+ #
10
+ # # Plain Mail (no Rails):
11
+ # Mail.defaults { delivery_method Mailkite::DeliveryMethod, api_key: ENV["MAILKITE_API_KEY"] }
12
+ #
13
+ # The `mail` gem is NOT a runtime dependency of this gem — it is required
14
+ # lazily here, on instantiation, so `require "mailkite"` stays zero-dependency.
15
+
16
+ module Mailkite
17
+ class DeliveryMethod
18
+ # Raised when a Mail::Message uses a feature the send API has no
19
+ # equivalent for (custom headers, inline cid: attachments, …). Refusing
20
+ # loudly beats silently dropping part of the message.
21
+ class UnsupportedFeatureError < StandardError; end
22
+
23
+ # Top-level headers the conversion consumes, plus the structural headers
24
+ # that only describe the MIME document (the API composes its own MIME).
25
+ # Anything else raises UnsupportedFeatureError — POST /v1/send takes no
26
+ # custom headers.
27
+ HANDLED_HEADERS = %w[
28
+ from to cc bcc subject reply-to in-reply-to
29
+ date message-id mime-version content-type content-transfer-encoding
30
+ ].freeze
31
+
32
+ attr_reader :settings
33
+
34
+ # settings: api_key (falls back to ENV["MAILKITE_API_KEY"]), optional
35
+ # base_url, or bring your own `client` — anything with `send(message)`
36
+ # (e.g. a Mailkite::Client, or a stub in tests). Takes precedence over
37
+ # api_key.
38
+ def initialize(settings = {})
39
+ require "mail" # lazy — only delivery-method users need the mail gem
40
+ @settings = settings
41
+ @client = settings[:client]
42
+ return if @client
43
+
44
+ api_key = settings[:api_key] || ENV["MAILKITE_API_KEY"]
45
+ if api_key.nil? || api_key.empty?
46
+ raise ArgumentError, "MailKite API key missing — pass api_key: in mailkite_settings or set MAILKITE_API_KEY"
47
+ end
48
+ @client = Client.new(api_key, settings[:base_url] || DEFAULT_BASE_URL)
49
+ end
50
+
51
+ # Deliver a Mail::Message via POST /v1/send. Returns the API response hash
52
+ # ({ "id" => …, "status" => … }); API failures raise Mailkite::Error.
53
+ def deliver!(mail)
54
+ @client.send(payload_for(mail))
55
+ end
56
+
57
+ private
58
+
59
+ # Convert a Mail::Message into a send-request body
60
+ # (sdks/spec/schemas/send-request.json). Raises on anything the API can't
61
+ # express rather than delivering a lossy message.
62
+ def payload_for(mail)
63
+ reject_custom_headers(mail)
64
+
65
+ from = addresses(mail[:from]).first
66
+ raise ArgumentError, "mail is missing a from address" if from.nil?
67
+ to = addresses(mail[:to])
68
+ raise ArgumentError, "mail is missing to recipients" if to.empty?
69
+
70
+ payload = { "from" => from, "to" => to }
71
+ cc = addresses(mail[:cc])
72
+ payload["cc"] = cc unless cc.empty?
73
+ bcc = addresses(mail[:bcc])
74
+ payload["bcc"] = bcc unless bcc.empty?
75
+ payload["subject"] = mail.subject unless mail.subject.nil?
76
+
77
+ reply_to = addresses(mail[:reply_to])
78
+ payload["replyTo"] = reply_to.join(", ") unless reply_to.empty?
79
+ in_reply_to = Array(mail.in_reply_to)
80
+ unless in_reply_to.empty?
81
+ payload["inReplyTo"] = in_reply_to.map { |id| id.start_with?("<") ? id : "<#{id}>" }.join(" ")
82
+ end
83
+
84
+ payload.merge(body_fields(mail)).merge(attachment_fields(mail))
85
+ end
86
+
87
+ # html/text from the message body: html_part/text_part when multipart,
88
+ # else the body under its own mime type. Any leftover MIME part that is
89
+ # neither the body nor an attachment has no API equivalent → raise.
90
+ def body_fields(mail)
91
+ fields = {}
92
+ if mail.multipart?
93
+ html = mail.html_part
94
+ text = mail.text_part
95
+ fields["html"] = html.decoded if html
96
+ fields["text"] = text.decoded if text
97
+ consumed = [html, text].compact + mail.attachments.to_a
98
+ leftover = mail.all_parts.reject { |p| p.multipart? || consumed.any? { |c| c.equal?(p) } }
99
+ unless leftover.empty?
100
+ raise UnsupportedFeatureError,
101
+ "the MailKite send API cannot express the #{leftover.first.mime_type} MIME part — only html/text bodies and attachments are supported"
102
+ end
103
+ else
104
+ body = mail.body.decoded
105
+ unless body.empty?
106
+ fields[mail.mime_type == "text/html" ? "html" : "text"] = body
107
+ end
108
+ end
109
+ fields
110
+ end
111
+
112
+ # Attachments become { filename, content: base64, contentType }. Inline
113
+ # (cid:) parts raise — the API has no Content-ID support, so embedded
114
+ # images would render broken.
115
+ def attachment_fields(mail)
116
+ return {} if mail.attachments.empty?
117
+
118
+ list = mail.attachments.map do |part|
119
+ if part.inline?
120
+ raise UnsupportedFeatureError,
121
+ "inline (cid:) attachments are not supported by the MailKite send API — attach the file normally or host the image at a URL"
122
+ end
123
+ {
124
+ "filename" => part.filename,
125
+ "content" => Base64.strict_encode64(part.body.decoded),
126
+ "contentType" => part.mime_type,
127
+ }
128
+ end
129
+ { "attachments" => list }
130
+ end
131
+
132
+ # POST /v1/send takes no custom headers (the schema is
133
+ # additionalProperties: false) — refuse them instead of silently dropping.
134
+ def reject_custom_headers(mail)
135
+ mail.header.fields.each do |field|
136
+ name = field.name.to_s.downcase
137
+ next if HANDLED_HEADERS.include?(name)
138
+
139
+ raise UnsupportedFeatureError,
140
+ "the MailKite send API has no support for the #{field.name} header — remove it, or deliver this message over SMTP relay instead"
141
+ end
142
+ end
143
+
144
+ # Formatted addresses for a header field (display names kept — the API
145
+ # parses RFC 5322 mailboxes); [] when the field is absent.
146
+ def addresses(field)
147
+ field.nil? ? [] : Array(field.formatted)
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,16 @@
1
+ # Docs: docs/integrations/rails-delivery-method.md
2
+ #
3
+ # Rails glue: registers :mailkite as an ActionMailer delivery method, so
4
+ # config.action_mailer.delivery_method = :mailkite
5
+ # just works. Loaded from lib/mailkite.rb only when Rails is present; outside
6
+ # Rails, register Mailkite::DeliveryMethod on `mail` directly.
7
+
8
+ module Mailkite
9
+ class Railtie < ::Rails::Railtie
10
+ initializer "mailkite.add_delivery_method", before: "action_mailer.set_configs" do
11
+ ActiveSupport.on_load(:action_mailer) do
12
+ ActionMailer::Base.add_delivery_method :mailkite, Mailkite::DeliveryMethod
13
+ end
14
+ end
15
+ end
16
+ end
data/lib/mailkite.rb CHANGED
@@ -15,7 +15,7 @@ require "base64"
15
15
  require "cgi"
16
16
 
17
17
  module Mailkite
18
- VERSION = "0.11.0"
18
+ VERSION = "0.12.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
@@ -337,6 +337,10 @@ module Mailkite
337
337
  request("POST", "/api/routes", body)
338
338
  end
339
339
 
340
+ def deleteRoute(id)
341
+ request("DELETE", "/api/routes/#{id}")
342
+ end
343
+
340
344
  # --- Templates ------------------------------------------------------
341
345
  def listTemplates
342
346
  request("GET", "/api/templates")
@@ -476,3 +480,8 @@ module Mailkite
476
480
  end
477
481
  end
478
482
  end
483
+
484
+ # ActionMailer / Mail integration (config.action_mailer.delivery_method = :mailkite).
485
+ # The `mail` gem is not a runtime dependency — DeliveryMethod requires it lazily.
486
+ require_relative "mailkite/delivery_method"
487
+ require_relative "mailkite/railtie" if defined?(::Rails::Railtie)
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailkite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.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-29 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2026-07-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mail
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.7'
13
27
  description: Send and manage email over your own authenticated domain with MailKite.
14
28
  email:
15
29
  executables: []
@@ -17,6 +31,8 @@ extensions: []
17
31
  extra_rdoc_files: []
18
32
  files:
19
33
  - lib/mailkite.rb
34
+ - lib/mailkite/delivery_method.rb
35
+ - lib/mailkite/railtie.rb
20
36
  homepage: https://mailkite.dev/docs/libraries
21
37
  licenses:
22
38
  - MIT