courrier 0.9.0 → 0.11.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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +16 -24
  4. data/README.md +178 -74
  5. data/courrier.gemspec +4 -4
  6. data/lib/courrier/configuration.rb +2 -4
  7. data/lib/courrier/email/provider.rb +14 -6
  8. data/lib/courrier/email/providers/base.rb +7 -2
  9. data/lib/courrier/email/providers/cloudflare.rb +35 -0
  10. data/lib/courrier/email/providers/lettermint.rb +31 -0
  11. data/lib/courrier/email/providers/loops.rb +1 -1
  12. data/lib/courrier/email/providers/mailgun.rb +1 -1
  13. data/lib/courrier/email/providers/mailjet.rb +1 -1
  14. data/lib/courrier/email/providers/mailpace.rb +1 -1
  15. data/lib/courrier/email/providers/postmark.rb +1 -1
  16. data/lib/courrier/email/providers/resend.rb +1 -1
  17. data/lib/courrier/email/providers/sendgrid.rb +1 -1
  18. data/lib/courrier/email/providers/ses.rb +75 -0
  19. data/lib/courrier/email/providers/smtp2go.rb +29 -0
  20. data/lib/courrier/email/providers/sparkpost.rb +1 -1
  21. data/lib/courrier/email/providers/userlist.rb +1 -1
  22. data/lib/courrier/email/request.rb +1 -1
  23. data/lib/courrier/email/transformer.rb +9 -9
  24. data/lib/courrier/email.rb +50 -38
  25. data/lib/courrier/errors.rb +0 -2
  26. data/lib/courrier/markdown.rb +52 -0
  27. data/lib/courrier/test.rb +38 -0
  28. data/lib/courrier/test_helper.rb +65 -0
  29. data/lib/courrier/version.rb +1 -1
  30. data/lib/courrier.rb +2 -2
  31. metadata +18 -31
  32. data/app/controllers/courrier/previews/cleanups_controller.rb +0 -13
  33. data/app/controllers/courrier/previews_controller.rb +0 -23
  34. data/app/views/courrier/previews/index.html.erb +0 -171
  35. data/config/routes.rb +0 -8
  36. data/lib/courrier/configuration/inbox.rb +0 -21
  37. data/lib/courrier/email/providers/inbox/default.html.erb +0 -126
  38. data/lib/courrier/email/providers/inbox.rb +0 -83
  39. data/lib/courrier/engine.rb +0 -7
  40. data/lib/courrier/jobs/email_delivery_job.rb +0 -23
  41. data/lib/courrier/railtie.rb +0 -23
  42. data/lib/courrier/tasks/courrier.rake +0 -13
  43. data/lib/generators/courrier/email_generator.rb +0 -42
  44. data/lib/generators/courrier/install_generator.rb +0 -11
  45. data/lib/generators/courrier/templates/email/password_reset.rb.tt +0 -29
  46. data/lib/generators/courrier/templates/email/welcome.rb.tt +0 -43
  47. data/lib/generators/courrier/templates/email.rb.tt +0 -15
  48. data/lib/generators/courrier/templates/initializer.rb.tt +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a3d93b4337d15e066ffa7ed4626dd254231ee744940de07b7b76be8714afbde
4
- data.tar.gz: d7ef7a3ed1a8600581b6bdf13f63072c49ad138ad52384e1c358dbcd8f8a45b2
3
+ metadata.gz: d793cbc73ad9612cbb5e010e6aed85f9885e41fc8b672d16f82a6d155f63b726
4
+ data.tar.gz: 1143fc17abc330c3f94192ec95aea7618583266491f109b62aee3178826ede97
5
5
  SHA512:
6
- metadata.gz: 32d2fba728012eb703ca67044484a2f0caf0177ee0f341b6973566a50136f6531dfc37edfe7347511b4de67291af0364f6f03ad4c22247f5bbd72ca306e13455
7
- data.tar.gz: 5a3ea2ea5fb0637f025a3577d6e1004a66478e0929b96752b0fdea302af95f6c88af3bed801265dc14f6645a8014adb781cd1cc04ee1809bedf76ca892f4c4f0
6
+ metadata.gz: 64991e00fdb46c81164c29ffc7dc9de6078bcbc6cad12407355424f19f54e3a767e8732abf1438105d1f14b3ebe8ecf8367aa88bd7e53fadd7787fa8dd163609
7
+ data.tar.gz: eed7664f6a7211fc98e8cd53e0dc24ad1784e5373575c006feb04fb7d3a2706da3127c0db801b3c960697f774cd3df68df3622b975f365ed5fdfa211327aa3d3
data/Gemfile CHANGED
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  gemspec
6
6
 
7
7
  group :development do
8
- gem "standard", "~> 1.49"
8
+ gem "standard", "~> 1.54.0"
9
9
  end
10
10
 
11
11
  group :development, :test do
data/Gemfile.lock CHANGED
@@ -1,18 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- courrier (0.9.0)
5
- launchy (>= 3.1, < 4)
4
+ courrier (0.11.0)
5
+ logger (>= 1.5, < 3)
6
6
  nokogiri (>= 1.18, < 2)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- addressable (2.8.7)
12
- public_suffix (>= 2.0.2, < 7.0)
13
11
  ast (2.4.3)
14
- childprocess (5.1.0)
15
- logger (~> 1.5)
16
12
  date (3.4.1)
17
13
  debug (1.10.0)
18
14
  irb (~> 1.10)
@@ -24,18 +20,14 @@ GEM
24
20
  reline (>= 0.4.2)
25
21
  json (2.11.1)
26
22
  language_server-protocol (3.17.0.4)
27
- launchy (3.1.1)
28
- addressable (~> 2.8)
29
- childprocess (~> 5.0)
30
- logger (~> 1.6)
31
23
  lint_roller (1.1.0)
32
24
  logger (1.7.0)
33
- minitest (5.25.5)
34
- nokogiri (1.18.8-arm64-darwin)
25
+ minitest (5.27.0)
26
+ nokogiri (1.19.3-arm64-darwin)
35
27
  racc (~> 1.4)
36
- nokogiri (1.18.8-x86_64-darwin)
28
+ nokogiri (1.19.3-x86_64-darwin)
37
29
  racc (~> 1.4)
38
- nokogiri (1.18.8-x86_64-linux-gnu)
30
+ nokogiri (1.19.3-x86_64-linux-gnu)
39
31
  racc (~> 1.4)
40
32
  parallel (1.27.0)
41
33
  parser (3.3.8.0)
@@ -44,11 +36,10 @@ GEM
44
36
  pp (0.6.2)
45
37
  prettyprint
46
38
  prettyprint (0.2.0)
47
- prism (1.4.0)
39
+ prism (1.9.0)
48
40
  psych (5.2.3)
49
41
  date
50
42
  stringio
51
- public_suffix (6.0.2)
52
43
  racc (1.8.1)
53
44
  rainbow (3.1.1)
54
45
  rake (13.2.1)
@@ -57,7 +48,7 @@ GEM
57
48
  regexp_parser (2.10.0)
58
49
  reline (0.6.1)
59
50
  io-console (~> 0.5)
60
- rubocop (1.75.3)
51
+ rubocop (1.84.2)
61
52
  json (~> 2.3)
62
53
  language_server-protocol (~> 3.17.0.2)
63
54
  lint_roller (~> 1.1.0)
@@ -65,21 +56,21 @@ GEM
65
56
  parser (>= 3.3.0.2)
66
57
  rainbow (>= 2.2.2, < 4.0)
67
58
  regexp_parser (>= 2.9.3, < 3.0)
68
- rubocop-ast (>= 1.44.0, < 2.0)
59
+ rubocop-ast (>= 1.49.0, < 2.0)
69
60
  ruby-progressbar (~> 1.7)
70
61
  unicode-display_width (>= 2.4.0, < 4.0)
71
- rubocop-ast (1.44.1)
62
+ rubocop-ast (1.49.1)
72
63
  parser (>= 3.3.7.2)
73
- prism (~> 1.4)
64
+ prism (~> 1.7)
74
65
  rubocop-performance (1.25.0)
75
66
  lint_roller (~> 1.1)
76
67
  rubocop (>= 1.75.0, < 2.0)
77
68
  rubocop-ast (>= 1.38.0, < 2.0)
78
69
  ruby-progressbar (1.13.0)
79
- standard (1.49.0)
70
+ standard (1.54.0)
80
71
  language_server-protocol (~> 3.17.0.2)
81
72
  lint_roller (~> 1.0)
82
- rubocop (~> 1.75.2)
73
+ rubocop (~> 1.84.0)
83
74
  standard-custom (~> 1.0.0)
84
75
  standard-performance (~> 1.8)
85
76
  standard-custom (1.0.2)
@@ -91,10 +82,11 @@ GEM
91
82
  stringio (3.1.7)
92
83
  unicode-display_width (3.1.4)
93
84
  unicode-emoji (~> 4.0, >= 4.0.4)
94
- unicode-emoji (4.0.4)
85
+ unicode-emoji (4.2.0)
95
86
 
96
87
  PLATFORMS
97
88
  arm64-darwin-23
89
+ arm64-darwin-24
98
90
  x86_64-darwin-23
99
91
  x86_64-linux
100
92
 
@@ -103,7 +95,7 @@ DEPENDENCIES
103
95
  debug (~> 1.9, >= 1.9.2)
104
96
  minitest (~> 5.25, >= 5.25.5)
105
97
  rake (~> 13.2, >= 13.2.1)
106
- standard (~> 1.49)
98
+ standard (~> 1.54.0)
107
99
 
108
100
  BUNDLED WITH
109
101
  2.6.8
data/README.md CHANGED
@@ -38,22 +38,24 @@ Add the gem:
38
38
  ```bash
39
39
  bundle add courrier
40
40
  ```
41
+ > [!tip]
42
+ > For **Rails** apps, use [`rails_courrier`](https://github.com/Rails-Designer/rails_courrier) instead. It includes generators, ActiveJob support (`deliver_later`), inbox previews and more.
41
43
 
42
- Generate the configuration file:
43
- ```bash
44
- bin/rails generate courrier:install
45
- ```
44
+ Configure Courrier in your app:
45
+ ```ruby
46
+ Courrier.configure do |config|
47
+ config.email = {
48
+ provider: "postmark",
49
+ api_key: "your-api-key"
50
+ }
46
51
 
47
- This creates `config/initializers/courrier.rb` for configuring email providers and default settings.
52
+ config.from = "devs@example.com"
53
+ end
54
+ ```
48
55
 
49
56
 
50
57
  ## Usage
51
58
 
52
- Generate a new email:
53
- ```bash
54
- bin/rails generate courrier:email Order
55
- ```
56
-
57
59
  ```ruby
58
60
  class OrderEmail < Courrier::Email
59
61
  def subject = "Here is your order!"
@@ -74,8 +76,6 @@ end
74
76
  # OrderEmail.deliver to: "recipient@railsdesigner.com"
75
77
  ```
76
78
 
77
- 💡 Write your email content using the [Minimal Email Editor](https://railsdesigner.com/minimal-email-editor/).
78
-
79
79
 
80
80
  ## Configuration
81
81
 
@@ -93,8 +93,13 @@ Courrier.configure do |config|
93
93
  config.default_url_options = { host: "railsdesigner.com" }
94
94
 
95
95
  # Provider-specific configuration
96
+ config.providers.cloudflare.account_id = "your-account-id"
96
97
  config.providers.loops.transactional_id = "default-template"
97
98
  config.providers.mailgun.domain = "notifications.railsdesigner.com"
99
+
100
+ config.providers.ses.region = "us-east-1"
101
+ config.providers.ses.access_key_id = "your-access-key-id"
102
+ config.providers.ses.secret_access_key = "your-secret-access-key"
98
103
  end
99
104
  ```
100
105
 
@@ -119,12 +124,30 @@ OrderEmail.deliver to: "recipient@railsdesigner.com",\
119
124
  Provider and API key settings can be overridden using environment variables (`COURRIER_PROVIDER` and `COURRIER_API_KEY`) for both global configuration and email class defaults.
120
125
 
121
126
 
127
+ ## Custom headers
128
+
129
+ Email classes can define custom HTTP headers that are sent with every email:
130
+ ```ruby
131
+ class OrderEmail < Courrier::Email
132
+ headers list_unsubscribe_post: "List-Unsubscribe=One-Click"
133
+
134
+ def subject = "Rails Icons now supports SVG sprites!"
135
+
136
+ def text = # …
137
+
138
+ def html = # …
139
+ end
140
+ ```
141
+
142
+ Useful for adding provider-specific headers like List-Unsubscribe for Postmark, X-Mailer identifiers or custom metadata headers required.
143
+
144
+
122
145
  ## Custom attributes
123
146
 
124
147
  Besides the standard email attributes (`from`, `to`, `reply_to`, etc.), you can pass any additional attributes that will be available in your email templates:
125
148
  ```ruby
126
149
  OrderEmail.deliver to: "recipient@railsdesigner.com",\
127
- download_url: downloads_path(token: "token")
150
+ download_url: "https://example.com/download?token=abc123"
128
151
  ```
129
152
 
130
153
  These custom attributes are accessible directly in your email class:
@@ -155,7 +178,7 @@ When sending an email through Courrier, a `Result` object is returned that provi
155
178
  ### Example
156
179
 
157
180
  ```ruby
158
- delivery = OrderEmail.deliver(to: "recipient@example.com")
181
+ delivery = OrderEmail.deliver to: "recipient@example.com"
159
182
 
160
183
  if delivery.success?
161
184
  puts "Email sent successfully!"
@@ -170,11 +193,17 @@ end
170
193
 
171
194
  Courrier supports these transactional email providers:
172
195
 
196
+ - [AWS SES](https://aws.amazon.com/ses/) — requires `aws-sigv4` gem
197
+ - [Cloudflare Email Service](https://developers.cloudflare.com/email-service/)
198
+ - [Lettermint](https://lettermint.co)
173
199
  - [Loops](https://loops.so)
174
200
  - [Mailgun](https://mailgun.com)
175
201
  - [MailPace](https://mailpace.com)
176
202
  - [Postmark](https://postmarkapp.com)
177
203
  - [Resend](https://resend.com)
204
+ - [SendGrid](https://sendgrid.com)
205
+ - [SMTP2GO](https://www.smtp2go.com/)
206
+ - [SparkPost](https://www.sparkpost.com/)
178
207
  - [Userlist](https://userlist.com)
179
208
 
180
209
 
@@ -183,36 +212,6 @@ Courrier supports these transactional email providers:
183
212
  Additional functionality to help with development and testing:
184
213
 
185
214
 
186
- ### Background jobs (Rails only)
187
-
188
- Use `deliver_later` to enqueue delivering using Rails' ActiveJob. You can set
189
- various ActiveJob-supported options in the email class, like so: `enqueue queue: "emails", wait: 5.minutes`.
190
-
191
- - `queue`, enqueue the email on the specified queue;
192
- - `wait`, enqueue the email to be delivered with a delay;
193
- - `wait_until`, enqueue the email to be delivered at (after) a specific date/time;
194
- - `priority`, enqueues the email with the specified priority.
195
-
196
-
197
- ### Inbox (Rails only)
198
-
199
- You can preview your emails in the inbox:
200
- ```ruby
201
- config.provider = "inbox"
202
-
203
- # And add to your routes:
204
- mount Courrier::Engine => "/courrier"
205
- ```
206
-
207
- If you want to automatically open every email in your default browser:
208
- ```ruby
209
- config.provider = "inbox"
210
- config.inbox.auto_open = true
211
- ```
212
-
213
- Emails are automatically cleared with `bin/rails tmp:clear`, or manually with `bin/rails courrier:clear`.
214
-
215
-
216
215
  ### Layout support
217
216
 
218
217
  Wrap your email content using layouts:
@@ -262,17 +261,18 @@ Instead of defining `text` and `html` methods, you can create ERB template files
262
261
  ```ruby
263
262
  class OrderEmail < Courrier::Email
264
263
  def subject = "Your order is ready!"
264
+
265
265
  # text and html content will be loaded from template files
266
266
  end
267
267
  ```
268
268
 
269
- Create template files alongside your email class:
270
- - `app/emails/order_email.text.erb`
271
- - `app/emails/order_email.html.erb`
269
+ Create template files alongside your email class (default path is `courrier/emails`):
270
+ - `courrier/emails/order_email.text.erb`
271
+ - `courrier/emails/order_email.html.erb`
272
272
 
273
273
  Templates have access to all context options and instance variables:
274
274
  ```erb
275
- <!-- app/emails/order_email.html.erb -->
275
+ <!-- courrier/emails/order_email.html.erb -->
276
276
  <h1>Hello <%= name %>!</h1>
277
277
  <p>Your order #<%= order_id %> is ready for pickup.</p>
278
278
  ```
@@ -284,33 +284,69 @@ class OrderEmail < Courrier::Email
284
284
 
285
285
  def text = "Hello #{name}! Your order ##{order_id} is ready."
286
286
 
287
- # html will be loaded from app/emails/order_email.html.erb
287
+ # html will be loaded from courrier/emails/order_email.html.erb
288
288
  end
289
289
  ```
290
290
 
291
291
 
292
- ### Auto-generate text from HTML
292
+ ## Markdown support
293
293
 
294
- Automatically generate plain text versions from your HTML emails:
295
- ```ruby
296
- config.auto_generate_text = true # Defaults to false
297
- ```
294
+ Courrier supports rendering markdown content to HTML when a markdown gem is available. Simply bundle any supported markdown gem (`redcarpet`, `kramdown` or `commonmarker`) and it will be used.
298
295
 
299
296
 
300
- ### Email address helper
297
+ ### Markdown methods
301
298
 
302
- Compose email addresses with display names:
299
+ Define a `markdown` method in your email class:
303
300
  ```ruby
304
- class SignupsController < ApplicationController
305
- def create
306
- recipient = email_with_name("devs@railsdesigner.com", "Rails Designer Devs")
301
+ class OrderEmail < Courrier::Email
302
+ def subject = "Your order is ready!"
307
303
 
308
- WelcomeEmail.deliver to: recipient
304
+ def markdown
305
+ <<~MARKDOWN
306
+ # Hello #{name}!
307
+
308
+ Your order **##{order_id}** is ready for pickup.
309
+
310
+ ## Order Details
311
+ - Item: #{item_name}
312
+ - Price: #{price}
313
+ MARKDOWN
309
314
  end
310
315
  end
311
316
  ```
312
317
 
313
- In Plain Ruby Objects:
318
+
319
+ ### Markdown templates
320
+
321
+ Create markdown template files alongside your email class (default path is `courrier/emails`):
322
+ - `courrier/emails/order_email.md.erb`
323
+ - `courrier/emails/order_email.markdown.erb`
324
+
325
+ ```erb
326
+ <!-- courrier/emails/order_email.md.erb -->
327
+ # Hello <%= name %>!
328
+
329
+ Your order **#<%= order_id %>** is ready for pickup.
330
+
331
+ ## Order Details
332
+ - Item: <%= item_name %>
333
+ - Price: <%= price %>
334
+ ```
335
+
336
+ Method definitions take precedence over template files. You can mix approaches. For example, define `text` in a method and use a markdown template for HTML content.
337
+
338
+
339
+ ### Auto-generate text from HTML
340
+
341
+ Automatically generate plain text versions from your HTML emails:
342
+ ```ruby
343
+ config.auto_generate_text = true # defaults to false
344
+ ```
345
+
346
+
347
+ ### Email address helper
348
+
349
+ Compose email addresses with display names:
314
350
  ```ruby
315
351
  class Signup
316
352
  include Courrier::Email::Address
@@ -329,8 +365,8 @@ end
329
365
  Use Ruby's built-in Logger for development and testing:
330
366
 
331
367
  ```ruby
332
- config.provider = "logger" # outputs emails to STDOUT
333
- config.logger = custom_logger # optional: defaults to ::Logger.new($stdout)
368
+ config.provider = "logger" # outputs emails to STDOUT
369
+ config.logger = custom_logger # optional: defaults to ::Logger.new($stdout)
334
370
  ```
335
371
 
336
372
 
@@ -355,6 +391,82 @@ config.provider = "CustomProvider"
355
391
  Check the [existing providers](https://github.com/Rails-Designer/courrier/tree/main/lib/courrier/email/providers) for implementation examples.
356
392
 
357
393
 
394
+ ### Testing
395
+
396
+ Courrier provides `Test` and `TestHelper` for testing email delivery, similar to Action Mailer's testing API.
397
+
398
+ Access all delivered emails:
399
+ ```ruby
400
+ # Clear deliveries between tests
401
+ Courrier::Test.clear!
402
+
403
+ # Access all deliveries
404
+ Courrier::Test.deliveries
405
+ ```
406
+
407
+ Each delivery record contains:
408
+
409
+ - `email_class`; the email class name
410
+ - `to`, `from`, `reply_to`, `cc`, `bcc`; email addresses
411
+ - `subject`; email subject
412
+ - `body` - Hash with `:text` and `:html` keys
413
+ - `headers`; custom headers
414
+ - `provider`; provider used
415
+ - `result`; result object with `success?` method
416
+ - `timestamp`; delivery time
417
+
418
+ Include the helper in your test class for assertions:
419
+ ```ruby
420
+ class OrderTest < Minitest::Test
421
+ include Courrier::TestHelper
422
+
423
+ def setup
424
+ Courrier::Test.clear!
425
+ end
426
+
427
+ def test_sends_confirmation_email
428
+ order = Order.create! product: "Widget", customer_email: "customer@example.com"
429
+
430
+ OrderEmail.deliver to: order.customer_email, order: order
431
+
432
+ assert_emails_delivered 1
433
+ assert_email_delivered to: "customer@example.com"
434
+ assert_email_delivered OrderEmail, subject: "Order"
435
+ end
436
+
437
+ def test_no_emails_when_order_cancelled
438
+ order = Order.create! product: "Widget", status: :cancelled
439
+
440
+ assert_no_emails_delivered
441
+ end
442
+ end
443
+ ```
444
+
445
+ Available assertions:
446
+
447
+ - `assert_emails_delivered(count)`; assert the number of emails delivered
448
+ - `assert_no_emails_delivered`; assert no emails were delivered
449
+ - `assert_email_delivered(email_class, to:, from:, subject:, provider:)`; assert an email matching criteria was delivered
450
+
451
+
452
+ ### Delivery callbacks
453
+
454
+ Hook into the email delivery lifecycle with `before_deliver` and `after_deliver` callbacks:
455
+ ```ruby
456
+ class OrderEmail < Courrier::Email
457
+ before_deliver do |email|
458
+ puts "Sending to #{email.options.to}" # access email options, abort delivery by returning false
459
+ end
460
+
461
+ after_deliver do |email, result|
462
+ puts "Delivered: #{result.success?}" # access email and delivery result
463
+ end
464
+ end
465
+ ```
466
+
467
+ Callbacks are isolated per class (subclasses don't inherit parent callbacks).
468
+
469
+
358
470
  ## Newsletter subscriptions
359
471
 
360
472
  Manage subscribers across popular email marketing platforms:
@@ -401,6 +513,7 @@ config.subscriber = {
401
513
  }
402
514
  ```
403
515
 
516
+
404
517
  ### Custom providers
405
518
 
406
519
  Create custom providers by inheriting from `Courrier::Subscriber::Base`:
@@ -440,20 +553,11 @@ See [existing providers](https://github.com/Rails-Designer/courrier/tree/main/li
440
553
 
441
554
  ## FAQ
442
555
 
443
- ### Is this a replacement for ActionMailer?
444
- Yes! While different in approach, Courrier can fully replace ActionMailer. It's a modern alternative that focuses on API-based delivery. The main difference is in how emails are structured - Courrier uses a more straightforward, class-based approach.
445
-
446
556
  ### Is this for Rails only?
447
- Not at all! While Courrier has some Rails-specific goodies (like the inbox preview feature and generators), it works great with any Ruby application.
557
+ Not at all! Courrier works with any Ruby application. For Rails apps, use [`rails_courrier`](https://github.com/Rails-Designer/rails_courrier).
448
558
 
449
559
  ### Can it send using SMTP?
450
- No - Courrier is specifically built for API-based email delivery. If SMTP is needed, ActionMailer would be a better choices.
451
-
452
- ### Can separate view templates be created (like ActionMailer)?
453
- The approach is different here. Instead of separate view files, email content is defined right in the email class using `text` and `html` methods. Layouts can be used to share common templates. This makes emails more self-contained and easier to reason about.
454
-
455
- ### What's the main benefit over ActionMailer?
456
- Courrier offers a simpler, more modern approach to sending emails. Each email is a standalone class, configuration is straightforward (typically just only an API key is needed) and it packs few quality-of-life features (like the inbox feature and auto-generate text version).
560
+ No. Courrier is specifically built for API-based email delivery.
457
561
 
458
562
 
459
563
  ## Contributing
data/courrier.gemspec CHANGED
@@ -10,16 +10,16 @@ Gem::Specification.new do |spec|
10
10
 
11
11
  spec.summary = "API-powered email delivery for Ruby apps"
12
12
  spec.description = "API-powered email delivery for Ruby apps with support for Postmark, SendGrid, Mailgun and more."
13
- spec.homepage = "https://railsdesigner.com/courrier/"
13
+ spec.homepage = "https://railsdesigner.com/open-source/courrier/"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.metadata["homepage_uri"] = spec.homepage
17
17
  spec.metadata["source_code_uri"] = "https://github.com/Rails-Designer/courrier/"
18
18
 
19
- spec.files = Dir["{bin,app,config,lib}/**/*", "Rakefile", "README.md", "courrier.gemspec", "Gemfile", "Gemfile.lock"]
19
+ spec.files = Dir["{bin,lib}/**/*", "Rakefile", "README.md", "courrier.gemspec", "Gemfile", "Gemfile.lock"]
20
20
 
21
- spec.required_ruby_version = ">= 3.2.0"
21
+ spec.required_ruby_version = ">= 4.0.0"
22
22
 
23
- spec.add_dependency "launchy", ">= 3.1", "< 4"
23
+ spec.add_dependency "logger", ">= 1.5", "< 3"
24
24
  spec.add_dependency "nokogiri", ">= 1.18", "< 2"
25
25
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "courrier/configuration/inbox"
4
3
  require "courrier/configuration/providers"
5
4
 
6
5
  module Courrier
@@ -22,7 +21,7 @@ module Courrier
22
21
  attr_accessor :email, :subscriber, :logger, :email_path, :layouts, :default_url_options, :auto_generate_text,
23
22
  :from, :reply_to, :cc, :bcc
24
23
 
25
- attr_reader :providers, :inbox
24
+ attr_reader :providers
26
25
 
27
26
  def initialize
28
27
  @email = {provider: "logger"}
@@ -41,7 +40,6 @@ module Courrier
41
40
  @bcc = nil
42
41
 
43
42
  @providers = Courrier::Configuration::Providers.new
44
- @inbox = Courrier::Configuration::Inbox.new
45
43
  end
46
44
 
47
45
  def provider
@@ -71,7 +69,7 @@ module Courrier
71
69
  private
72
70
 
73
71
  def default_email_path
74
- defined?(Rails) ? Rails.root.join("app", "emails").to_s : File.join("courrier", "emails")
72
+ File.join("courrier", "emails")
75
73
  end
76
74
  end
77
75
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "courrier/email/providers/base"
4
- require "courrier/email/providers/inbox"
4
+ require "courrier/email/providers/cloudflare"
5
+ require "courrier/email/providers/lettermint"
5
6
  require "courrier/email/providers/logger"
6
7
  require "courrier/email/providers/loops"
7
8
  require "courrier/email/providers/mailgun"
@@ -9,7 +10,9 @@ require "courrier/email/providers/mailjet"
9
10
  require "courrier/email/providers/mailpace"
10
11
  require "courrier/email/providers/postmark"
11
12
  require "courrier/email/providers/resend"
13
+ require "courrier/email/providers/ses"
12
14
  require "courrier/email/providers/sendgrid"
15
+ require "courrier/email/providers/smtp2go"
13
16
  require "courrier/email/providers/sparkpost"
14
17
  require "courrier/email/providers/userlist"
15
18
 
@@ -17,26 +20,30 @@ module Courrier
17
20
  class Email
18
21
  class Provider
19
22
  PROVIDERS = {
20
- inbox: Courrier::Email::Providers::Inbox,
23
+ cloudflare: Courrier::Email::Providers::Cloudflare,
21
24
  logger: Courrier::Email::Providers::Logger,
25
+ lettermint: Courrier::Email::Providers::Lettermint,
22
26
  loops: Courrier::Email::Providers::Loops,
23
27
  mailgun: Courrier::Email::Providers::Mailgun,
24
28
  mailjet: Courrier::Email::Providers::Mailjet,
25
29
  mailpace: Courrier::Email::Providers::Mailpace,
26
30
  postmark: Courrier::Email::Providers::Postmark,
27
31
  resend: Courrier::Email::Providers::Resend,
32
+ ses: Courrier::Email::Providers::Ses,
28
33
  sendgrid: Courrier::Email::Providers::Sendgrid,
34
+ smtp2go: Courrier::Email::Providers::Smtp2go,
29
35
  sparkpost: Courrier::Email::Providers::Sparkpost,
30
36
  userlist: Courrier::Email::Providers::Userlist
31
37
  }
32
38
 
33
- def initialize(provider: nil, api_key: nil, options: {}, provider_options: {}, context_options: {})
39
+ def initialize(provider: nil, api_key: nil, options: {}, provider_options: {}, context_options: {}, custom_headers: {})
34
40
  @provider = provider
35
41
  @api_key = api_key
36
42
 
37
43
  @options = options
38
44
  @provider_options = provider_options
39
45
  @context_options = context_options
46
+ @custom_headers = custom_headers
40
47
  end
41
48
 
42
49
  def deliver
@@ -47,7 +54,8 @@ module Courrier
47
54
  api_key: @api_key,
48
55
  options: @options,
49
56
  provider_options: @provider_options,
50
- context_options: @context_options
57
+ context_options: @context_options,
58
+ custom_headers: @custom_headers
51
59
  ).deliver
52
60
  end
53
61
 
@@ -70,7 +78,7 @@ module Courrier
70
78
  end
71
79
 
72
80
  def api_key_required_providers?
73
- !%w[logger inbox].include?(@provider.to_s)
81
+ !%w[logger].include?(@provider.to_s)
74
82
  end
75
83
 
76
84
  def api_key_blank?
@@ -78,7 +86,7 @@ module Courrier
78
86
  end
79
87
 
80
88
  def production?
81
- defined?(Rails) && Rails.env.production?
89
+ ENV["RACK_ENV"] == "production"
82
90
  end
83
91
  end
84
92
  end
@@ -6,11 +6,12 @@ module Courrier
6
6
  class Email
7
7
  module Providers
8
8
  class Base
9
- def initialize(api_key: nil, options: {}, provider_options: {}, context_options: {})
9
+ def initialize(api_key: nil, options: {}, provider_options: {}, context_options: {}, custom_headers: {})
10
10
  @api_key = api_key
11
11
  @options = options
12
12
  @provider_options = provider_options
13
13
  @context_options = context_options
14
+ @custom_headers = custom_headers
14
15
  end
15
16
 
16
17
  def deliver
@@ -31,7 +32,11 @@ module Courrier
31
32
 
32
33
  def content_type = "application/json"
33
34
 
34
- def headers = {}
35
+ def headers
36
+ default_headers.merge(@custom_headers)
37
+ end
38
+
39
+ def default_headers = {}
35
40
 
36
41
  def provider = self.class.name.split("::").last
37
42
  end