courrier 0.6.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +159 -26
  4. data/app/controllers/courrier/previews/cleanups_controller.rb +13 -0
  5. data/app/controllers/courrier/previews_controller.rb +23 -0
  6. data/app/views/courrier/previews/index.html.erb +171 -0
  7. data/config/routes.rb +8 -0
  8. data/courrier.gemspec +3 -3
  9. data/lib/courrier/configuration/{preview.rb → inbox.rb} +3 -3
  10. data/lib/courrier/configuration.rb +32 -6
  11. data/lib/courrier/email/options.rb +15 -0
  12. data/lib/courrier/email/provider.rb +22 -17
  13. data/lib/courrier/email/providers/base.rb +2 -1
  14. data/lib/courrier/email/providers/{preview → inbox}/default.html.erb +13 -6
  15. data/lib/courrier/email/providers/inbox.rb +83 -0
  16. data/lib/courrier/email/providers/logger.rb +22 -3
  17. data/lib/courrier/email/providers/loops.rb +1 -8
  18. data/lib/courrier/email/providers/resend.rb +32 -0
  19. data/lib/courrier/email/providers/userlist.rb +13 -13
  20. data/lib/courrier/email.rb +54 -11
  21. data/lib/courrier/engine.rb +7 -0
  22. data/lib/courrier/errors.rb +3 -1
  23. data/lib/courrier/jobs/email_delivery_job.rb +23 -0
  24. data/lib/courrier/subscriber/base.rb +51 -0
  25. data/lib/courrier/subscriber/beehiiv.rb +45 -0
  26. data/lib/courrier/subscriber/buttondown.rb +28 -0
  27. data/lib/courrier/subscriber/kit.rb +36 -0
  28. data/lib/courrier/subscriber/loops.rb +32 -0
  29. data/lib/courrier/subscriber/mailchimp.rb +39 -0
  30. data/lib/courrier/subscriber/mailerlite.rb +28 -0
  31. data/lib/courrier/subscriber/result.rb +41 -0
  32. data/lib/courrier/subscriber.rb +34 -0
  33. data/lib/courrier/tasks/courrier.rake +2 -2
  34. data/lib/courrier/version.rb +1 -1
  35. data/lib/courrier.rb +2 -0
  36. data/lib/generators/courrier/email_generator.rb +24 -1
  37. data/lib/generators/courrier/templates/email/password_reset.rb.tt +29 -0
  38. data/lib/generators/courrier/templates/email/welcome.rb.tt +43 -0
  39. data/lib/generators/courrier/templates/initializer.rb.tt +10 -5
  40. metadata +26 -8
  41. data/lib/courrier/email/providers/preview.rb +0 -51
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b2da5fe5fc7bb657449ed12d90c8443d6fa692339f9974fcbda7c4c726964ad8
4
- data.tar.gz: ad4fc570a0bdb7cb1bce3c214a21e550a725212e0f900e5d31fe1345d5c7b221
3
+ metadata.gz: e43b1cb6985e742ca84f68be14ddf25e72bf8f64a26ce7be151272983996ac45
4
+ data.tar.gz: ac7b82db6e5fd9975a76de6a630a4ac8e3f956595e175fc6d6c1ef18d9d4949c
5
5
  SHA512:
6
- metadata.gz: 7170f0e34c59ceee7b88c41865da67f558357058651a9508578adb5b0fec0d5da78bea1672aed8b24335128822784c1e5b23478804fb1a08273efece5129ae3f
7
- data.tar.gz: 89de9523761715879b487d62ca63576eb9783647a0e2d8baba5ef268b36c91d359d96c33386b06a3cd686af8e747cf548eaf74ea9654efde22030a52eaac5fe4
6
+ metadata.gz: 4f5ad1ecb424cca190a86bd10acbf69c906e3f7218724a3cdc29e8ce3e10c4bea4c1c43ba66d6de24af17f53c9db416c659e7b84aadd92fcece63b57ee5a13ce
7
+ data.tar.gz: 9050571fcc8050ecb6a92a321e466f92951c383d3ec1376809f70913440f38537f8245b37f2955bca3c263874d9de178818789dae89cc2a7bfe809c3d9d39eb9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- courrier (0.6.0)
4
+ courrier (0.8.0)
5
5
  launchy (>= 3.1, < 4)
6
6
  nokogiri (>= 1.18, < 2)
7
7
 
data/README.md CHANGED
@@ -1,12 +1,23 @@
1
1
  # Courrier
2
2
 
3
- Modern, API-powered email delivery for Ruby apps.
3
+ API-powered email delivery and newsletter subscription management for Ruby apps
4
4
 
5
- ![A cute cartoon mascot wearing a blue postal uniform with red scarf and cap, carrying a leather messenger bag, representing a modern email delivery system for Ruby applications](https://raw.githubusercontent.com/Rails-Designer/courrier/HEAD/.github/cover.jpg)
5
+ ![A cute cartoon mascot wearing a blue postal uniform with red scarf and cap, carrying a leather messenger bag, representing an API-powered email delivery gem for Ruby apps](https://raw.githubusercontent.com/Rails-Designer/courrier/HEAD/.github/cover.jpg)
6
6
 
7
7
  ```ruby
8
8
  # Quick example
9
+ class OrderEmail < Courrier::Email
10
+ def subject = "Here is your order!"
11
+
12
+ def text = "Thanks for ordering"
13
+
14
+ def html = "<p>Thanks for ordering</p>"
15
+ end
16
+
9
17
  OrderEmail.deliver to: "recipient@railsdesigner.com"
18
+
19
+ # Manage newsletter subscriptions
20
+ Courrier::Subscriber.create "subscriber@example.com"
10
21
  ```
11
22
 
12
23
  <a href="https://railsdesigner.com/" target="_blank">
@@ -72,8 +83,11 @@ Courrier uses a configuration system with three levels (from lowest to highest p
72
83
  1. **Global configuration**
73
84
  ```ruby
74
85
  Courrier.configure do |config|
75
- config.provider = "postmark"
76
- config.api_key = "xyz"
86
+ config.email = {
87
+ provider: "postmark",
88
+ api_key: "xyz"
89
+ }
90
+
77
91
  config.from = "devs@railsdesigner.com"
78
92
  config.default_url_options = { host: "railsdesigner.com" }
79
93
 
@@ -88,7 +102,7 @@ end
88
102
  class OrderEmail < Courrier::Email
89
103
  configure from: "orders@railsdesigner.com",
90
104
  cc: "records@railsdesigner.com",
91
- provider: "mailgun",
105
+ provider: "mailgun"
92
106
  end
93
107
  ```
94
108
 
@@ -104,11 +118,12 @@ OrderEmail.deliver to: "recipient@railsdesigner.com",\
104
118
  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.
105
119
 
106
120
 
107
- ## Custom Attributes
121
+ ## Custom attributes
108
122
 
109
123
  Besides the standard email attributes (`from`, `to`, `reply_to`, etc.), you can pass any additional attributes that will be available in your email templates:
110
124
  ```ruby
111
- OrderEmail.deliver to: "recipient@railsdesigner.com", download_url: downloads_path(token: "token")
125
+ OrderEmail.deliver to: "recipient@railsdesigner.com",\
126
+ download_url: downloads_path(token: "token")
112
127
  ```
113
128
 
114
129
  These custom attributes are accessible directly in your email class:
@@ -121,12 +136,12 @@ end
121
136
  ```
122
137
 
123
138
 
124
- ## Result Object
139
+ ## Result object
125
140
 
126
141
  When sending an email through Courrier, a `Result` object is returned that provides information about the delivery attempt. This object offers a simple interface to check the status and access response data.
127
142
 
128
143
 
129
- ### Available Methods
144
+ ### Available methods
130
145
 
131
146
  | Method | Return Type | Description |
132
147
  |:-------|:-----------|:------------|
@@ -156,32 +171,48 @@ Courrier supports these transactional email providers:
156
171
 
157
172
  - [Loops](https://loops.so)
158
173
  - [Mailgun](https://mailgun.com)
159
- - [Mailjet](https://mailjet.com)
160
174
  - [MailPace](https://mailpace.com)
161
175
  - [Postmark](https://postmarkapp.com)
162
- - [SendGrid](https://sendgrid.com)
163
- - [SparkPost](https://sparkpost.com)
176
+ - [Resend](https://resend.com)
164
177
  - [Userlist](https://userlist.com)
165
178
 
166
- ⚠️ Some providers still need manual verification of their implementation. If you're using one of these providers, please help verify the implementation by sharing your experience in [this GitHub issue](https://github.com/Rails-Designer/courrier/issues/4). 🙏
167
-
168
179
 
169
180
  ## More Features
170
181
 
171
- Additional functionality to help with development and email handling:
182
+ Additional functionality to help with development and testing:
183
+
184
+
185
+ ### Background jobs (Rails only)
186
+
187
+ Use `deliver_later` to enqueue delivering using Rails' ActiveJob. You can set
188
+ various ActiveJob-supported options in the email class, like so: `enqueue queue: "emails", wait: 5.minutes`.
189
+
190
+ - `queue`, enqueue the email on the specified queue;
191
+ - `wait`, enqueue the email to be delivered with a delay;
192
+ - `wait_until`, enqueue the email to be delivered at (after) a specific date/time;
193
+ - `priority`, enqueues the email with the specified priority.
194
+
195
+
196
+ ### Inbox (Rails only)
172
197
 
198
+ You can preview your emails in the inbox:
199
+ ```ruby
200
+ config.provider = "inbox"
173
201
 
174
- ### Email Preview
202
+ # And add to your routes:
203
+ mount Courrier::Engine => "/courrier"
204
+ ```
175
205
 
176
- Preview emails in your browser during development:
206
+ If you want to automatically open every email in your default browser:
177
207
  ```ruby
178
- config.provider = "preview" # Opens emails in your default browser
208
+ config.provider = "inbox"
209
+ config.inbox.auto_open = true
179
210
  ```
180
211
 
181
- Previews are automatically cleared with `bin/rails tmp:clear`, or manually with `bin/rails courrier:clear`.
212
+ Emails are automatically cleared with `bin/rails tmp:clear`, or manually with `bin/rails courrier:clear`.
182
213
 
183
214
 
184
- ### Layout Support
215
+ ### Layout support
185
216
 
186
217
  Wrap your email content using layouts:
187
218
  ```ruby
@@ -224,7 +255,7 @@ end
224
255
  ```
225
256
 
226
257
 
227
- ### Auto-generate Text from HTML
258
+ ### Auto-generate text from HTML
228
259
 
229
260
  Automatically generate plain text versions from your HTML emails:
230
261
  ```ruby
@@ -232,7 +263,7 @@ config.auto_generate_text = true # Defaults to false
232
263
  ```
233
264
 
234
265
 
235
- ### Email Address Helper
266
+ ### Email address helper
236
267
 
237
268
  Compose email addresses with display names:
238
269
  ```ruby
@@ -259,16 +290,17 @@ end
259
290
  ```
260
291
 
261
292
 
262
- ### Logger Provider
293
+ ### Logger provider
263
294
 
264
295
  Use Ruby's built-in Logger for development and testing:
265
296
 
266
297
  ```ruby
267
- config.provider = "logger" # Outputs emails to STDOUT
268
- config.logger = custom_logger # Optional: defaults to ::Logger.new($stdout)
298
+ config.provider = "logger" # outputs emails to STDOUT
299
+ config.logger = custom_logger # optional: defaults to ::Logger.new($stdout)
269
300
  ```
270
301
 
271
- ### Custom Providers
302
+
303
+ ### Custom providers
272
304
 
273
305
  Create your own provider by inheriting from `Courrier::Email::Providers::Base`:
274
306
  ```ruby
@@ -289,6 +321,107 @@ config.provider = "CustomProvider"
289
321
  Check the [existing providers](https://github.com/Rails-Designer/courrier/tree/main/lib/courrier/email/providers) for implementation examples.
290
322
 
291
323
 
324
+ ## Newsletter subscriptions
325
+
326
+ Manage subscribers across popular email marketing platforms:
327
+ ```ruby
328
+ Courrier.configure do |config|
329
+ config.subscriber = {
330
+ provider: "buttondown",
331
+ api_key: "your_api_key"
332
+ }
333
+ end
334
+ ```
335
+
336
+ ```ruby
337
+ # Add a subscriber
338
+ subscriber = Courrier::Subscriber.create "subscriber@example.com"
339
+
340
+ # Remove a subscriber
341
+ subscriber = Courrier::Subscriber.destroy "subscriber@example.com"
342
+
343
+ if subscriber.success?
344
+ puts "Subscriber added!"
345
+ else
346
+ puts "Error: #{subscriber.error}"
347
+ end
348
+ ```
349
+
350
+
351
+ ### Supported providers
352
+
353
+ - [Beehiiv](https://www.beehiiv.com/) - requires `publication_id`
354
+ - [Buttondown](https://buttondown.com)
355
+ - [Kit](https://kit.com/) (formerly ConvertKit) - requires `form_id`
356
+ - [Loops](https://loops.so/)
357
+ - [Mailchimp](https://mailchimp.com/) - requires `dc` and `list_id`
358
+ - [MailerLite](https://www.mailerlite.com/)
359
+
360
+ Provider-specific configuration:
361
+ ```ruby
362
+ config.subscriber = {
363
+ provider: "mailchimp",
364
+ api_key: "your_api_key",
365
+ dc: "us19",
366
+ list_id: "abc123"
367
+ }
368
+ ```
369
+
370
+ ### Custom providers
371
+
372
+ Create custom providers by inheriting from `Courrier::Subscriber::Base`:
373
+ ```ruby
374
+ class CustomSubscriberProvider < Courrier::Subscriber::Base
375
+ ENDPOINT_URL = "https://api.example.com/subscribers"
376
+
377
+ def create(email)
378
+ request(:post, ENDPOINT_URL, {"email" => email})
379
+ end
380
+
381
+ def destroy(email)
382
+ request(:delete, "#{ENDPOINT_URL}/#{email}")
383
+ end
384
+
385
+ private
386
+
387
+ def headers
388
+ {
389
+ "Authorization" => "Bearer #{@api_key}",
390
+ "Content-Type" => "application/json"
391
+ }
392
+ end
393
+ end
394
+ ```
395
+
396
+ Then configure it:
397
+ ```ruby
398
+ config.subscriber = {
399
+ provider: CustomSubscriberProvider,
400
+ api_key: "your_api_key"
401
+ }
402
+ ```
403
+
404
+ See [existing providers](https://github.com/Rails-Designer/courrier/tree/main/lib/courrier/subscriber) for more examples.
405
+
406
+
407
+ ## FAQ
408
+
409
+ ### Is this a replacement for ActionMailer?
410
+ 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.
411
+
412
+ ### Is this for Rails only?
413
+ Not at all! While Courrier has some Rails-specific goodies (like the inbox preview feature and generators), it works great with any Ruby application.
414
+
415
+ ### Can it send using SMTP?
416
+ No - Courrier is specifically built for API-based email delivery. If SMTP is needed, ActionMailer would be a better choices.
417
+
418
+ ### Can separate view templates be created (like ActionMailer)?
419
+ 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.
420
+
421
+ ### What's the main benefit over ActionMailer?
422
+ 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).
423
+
424
+
292
425
  ## Contributing
293
426
 
294
427
  This project uses [Standard](https://github.com/testdouble/standard) for formatting Ruby code. Please make sure to run `rake` before submitting pull requests.
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Courrier
4
+ module Previews
5
+ class CleanupsController < ActionController::Base
6
+ def create
7
+ system("bin/rails courrier:clear")
8
+
9
+ redirect_to root_path
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Courrier
4
+ class PreviewsController < ActionController::Base
5
+ def index
6
+ @emails = emails.map { Courrier::Email::Providers::Inbox::Email.from_file(_1) }
7
+ end
8
+
9
+ def show
10
+ file_path = File.join(Courrier.configuration.inbox.destination, params[:id])
11
+ content = File.read(file_path)
12
+
13
+ render html: content.html_safe, layout: false
14
+ end
15
+
16
+ private
17
+
18
+ def emails
19
+ @emails ||= Dir.glob("#{Courrier.configuration.inbox.destination}/*.html")
20
+ .sort_by { -File.basename(_1, ".html").to_i }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,171 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Courrier Inbox</title>
6
+
7
+ <style>
8
+ *, *::before, *::after { box-sizing: border-box; }
9
+ * { margin: 0; padding: 0; }
10
+ body { margin: 0; padding: 0; font-size: 16px; line-height: 1.5; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; background-color: rgb(241, 245, 249); }
11
+
12
+ .sidebar {
13
+ display: flex;
14
+ flex-direction: column;
15
+ position: sticky;
16
+ top: 0;
17
+ padding: .5rem;
18
+ width: min(350px, 33.3333%); height: 100dvh;
19
+ border-right: 1px solid rgb(226, 232, 240);
20
+ }
21
+
22
+ .sidebar__options {
23
+ position: sticky;
24
+ bottom: 0;
25
+ padding: .5rem;
26
+ background-color: rgb(241, 245, 249);
27
+ }
28
+
29
+ .sidebar__btn-clear {
30
+ border: none;
31
+ display: flex;
32
+ align-items: center;
33
+ justify-content: center;
34
+ column-gap: 0.25rem;
35
+ width: 100%;
36
+ padding: .5rem;
37
+ font-size: .875rem; line-height: 1.25rem;
38
+ font-weight: 500;
39
+ color: rgb(71, 85, 105);
40
+ background-color: rgb(226, 232, 240);
41
+ border-radius: .5rem;
42
+ cursor: default;
43
+
44
+ &:hover { background-color: rgb(203, 213, 225); }
45
+ &:active { transform: scale(.98); }
46
+
47
+ [data-slot="icon"] {
48
+ width: .875rem; height: .875rem;
49
+ }
50
+ }
51
+
52
+ .email-previews {
53
+ display: flex;
54
+ flex-direction: column;
55
+ flex: 1;
56
+ row-gap: .5rem;
57
+ overflow-y: auto;
58
+ width: 100%;
59
+ }
60
+
61
+ .email-preview {
62
+ display: flex;
63
+ flex-direction: row;
64
+ column-gap: .5rem;
65
+ width: 100%;
66
+ padding: .5rem .75rem;
67
+ text-decoration: none;
68
+ border-radius: .5rem;
69
+
70
+ &:hover {
71
+ background-color: rgba(226, 232, 240, .75);
72
+ }
73
+ }
74
+
75
+ .email-preview--empty {
76
+ display: none;
77
+ text-align: center;
78
+
79
+ &:only-child {
80
+ display: block;
81
+ }
82
+ }
83
+
84
+ .email-preview__avatar {
85
+ flex-shrink: 0;
86
+ padding: .25rem;
87
+ width: 1.5rem; height: 1.5rem;
88
+ background-color: rgb(203, 213, 225);
89
+ color: rgb(51, 65, 85);
90
+ border-radius: 9999px;
91
+ }
92
+
93
+ .email-preview__content {
94
+ font-size: 0.875rem; line-height: 1.25rem;
95
+ }
96
+
97
+ .email-preview__recipient {
98
+ font-size: 1rem; line-height: 1.5rem;
99
+ font-weight: 600;
100
+ letter-spacing: -.025em;
101
+ color: rgb(51, 65, 85);
102
+ }
103
+
104
+ .email-preview__subject {
105
+ margin-top: .125rem;
106
+ overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1;
107
+ color: rgb(100, 116, 139);
108
+ }
109
+ </style>
110
+ </head>
111
+ <body>
112
+ <div style="display: flex; column-gap: 1rem;">
113
+ <aside class="sidebar">
114
+ <ul class="email-previews">
115
+ <li class="email-preview--empty">
116
+ <p class="email-preview__subject">
117
+ No emails yet…
118
+ </p>
119
+ </li>
120
+
121
+ <% @emails.each do |email| %>
122
+ <li>
123
+ <%= link_to courrier.preview_path(email.filename), data: {remote: true}, class: "email-preview" do %>
124
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon" class="email-preview__avatar">
125
+ <path fill-rule="evenodd" d="M7.5 6a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM3.751 20.105a8.25 8.25 0 0 1 16.498 0 .75.75 0 0 1-.437.695A18.683 18.683 0 0 1 12 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 0 1-.437-.695Z" clip-rule="evenodd"/>
126
+ </svg>
127
+
128
+ <div class="email-preview__content">
129
+ <small class="email-preview__recipient">
130
+ <%= email.metadata.to %>
131
+ </small>
132
+
133
+ <p class="email-preview__subject">
134
+ <%= email.metadata.subject || "No subject" %>
135
+ </p>
136
+ </div>
137
+ <% end %>
138
+ </li>
139
+ <% end %>
140
+ </ul>
141
+
142
+ <div class="sidebar__options">
143
+ <%= button_to courrier.cleanup_path, class: "sidebar__btn-clear" do %>
144
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" data-slot="icon">
145
+ <path fill-rule="evenodd" d="M16.5 4.478v.227a48.816 48.816 0 0 1 3.878.512.75.75 0 1 1-.256 1.478l-.209-.035-1.005 13.07a3 3 0 0 1-2.991 2.77H8.084a3 3 0 0 1-2.991-2.77L4.087 6.66l-.209.035a.75.75 0 0 1-.256-1.478A48.567 48.567 0 0 1 7.5 4.705v-.227c0-1.564 1.213-2.9 2.816-2.951a52.662 52.662 0 0 1 3.369 0c1.603.051 2.815 1.387 2.815 2.951Zm-6.136-1.452a51.196 51.196 0 0 1 3.273 0C14.39 3.05 15 3.684 15 4.478v.113a49.488 49.488 0 0 0-6 0v-.113c0-.794.609-1.428 1.364-1.452Zm-.355 5.945a.75.75 0 1 0-1.5.058l.347 9a.75.75 0 1 0 1.499-.058l-.346-9Zm5.48.058a.75.75 0 1 0-1.498-.058l-.347 9a.75.75 0 0 0 1.5.058l.345-9Z" clip-rule="evenodd"/>
146
+ </svg>
147
+
148
+ Clear inbox
149
+ <% end %>
150
+ </div>
151
+ </aside>
152
+
153
+ <article style="flex: 1;" id="email-preview">
154
+ </article>
155
+ </div>
156
+
157
+ <script>
158
+ document.querySelectorAll("a[data-remote]").forEach(link => {
159
+ link.addEventListener("click", (event) => {
160
+ event.preventDefault();
161
+
162
+ fetch(link.href)
163
+ .then(response => response.text())
164
+ .then(html => {
165
+ document.getElementById("email-preview").innerHTML = html;
166
+ });
167
+ });
168
+ });
169
+ </script>
170
+ </body>
171
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ Courrier::Engine.routes.draw do
4
+ resources :previews, only: %w[show], constraints: {id: /.*\.html/}
5
+ resource :cleanup, only: %w[create], module: "previews"
6
+
7
+ root "previews#index"
8
+ end
data/courrier.gemspec CHANGED
@@ -8,15 +8,15 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Rails Designer"]
9
9
  spec.email = ["devs@railsdesigner.com"]
10
10
 
11
- spec.summary = "Modern, API-powered email delivery for Rails apps"
12
- spec.description = "Modern, API-powered email delivery for Ruby apps with support for Postmark, SendGrid, Mailgun and more."
11
+ spec.summary = "API-powered email delivery for Ruby apps"
12
+ spec.description = "API-powered email delivery for Ruby apps with support for Postmark, SendGrid, Mailgun and more."
13
13
  spec.homepage = "https://railsdesigner.com/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,db,lib,public}/**/*", "Rakefile", "README.md", "courrier.gemspec", "Gemfile", "Gemfile.lock"]
19
+ spec.files = Dir["{bin,app,config,lib}/**/*", "Rakefile", "README.md", "courrier.gemspec", "Gemfile", "Gemfile.lock"]
20
20
 
21
21
  spec.required_ruby_version = ">= 3.2.0"
22
22
 
@@ -2,13 +2,13 @@
2
2
 
3
3
  module Courrier
4
4
  class Configuration
5
- class Preview
5
+ class Inbox
6
6
  attr_accessor :destination, :auto_open, :template_path
7
7
 
8
8
  def initialize
9
9
  @destination = default_destination
10
- @auto_open = true
11
- @template_path = File.expand_path("../../../courrier/email/providers/preview/default.html.erb", __FILE__)
10
+ @auto_open = false
11
+ @template_path = File.expand_path("../../../courrier/email/providers/inbox/default.html.erb", __FILE__)
12
12
  end
13
13
 
14
14
  private
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "courrier/configuration/preview"
3
+ require "courrier/configuration/inbox"
4
4
  require "courrier/configuration/providers"
5
5
 
6
6
  module Courrier
@@ -19,13 +19,15 @@ module Courrier
19
19
  end
20
20
 
21
21
  class Configuration
22
- attr_accessor :provider, :api_key, :logger, :email_path, :layouts, :default_url_options, :auto_generate_text,
22
+ attr_accessor :email, :subscriber, :logger, :email_path, :layouts, :default_url_options, :auto_generate_text,
23
23
  :from, :reply_to, :cc, :bcc
24
- attr_reader :providers, :preview
24
+
25
+ attr_reader :providers, :inbox
25
26
 
26
27
  def initialize
27
- @provider = "logger"
28
- @api_key = nil
28
+ @email = {provider: "logger"}
29
+ @subscriber = {}
30
+
29
31
  @logger = ::Logger.new($stdout)
30
32
  @email_path = default_email_path
31
33
 
@@ -39,7 +41,31 @@ module Courrier
39
41
  @bcc = nil
40
42
 
41
43
  @providers = Courrier::Configuration::Providers.new
42
- @preview = Courrier::Configuration::Preview.new
44
+ @inbox = Courrier::Configuration::Inbox.new
45
+ end
46
+
47
+ def provider
48
+ warn "[DEPRECATION] `provider` is deprecated. Use `email = { provider: '…' }` instead. Will be removed in 1.0.0"
49
+
50
+ @email[:provider]
51
+ end
52
+
53
+ def provider=(value)
54
+ warn "[DEPRECATION] `provider=` is deprecated. Use `email = { provider: '…' }` instead. Will be removed in 1.0.0"
55
+
56
+ @email[:provider] = value
57
+ end
58
+
59
+ def api_key
60
+ warn "[DEPRECATION] `api_key` is deprecated. Use `email = { api_key: '…' }` instead. Will be removed in 1.0.0"
61
+
62
+ @email[:api_key]
63
+ end
64
+
65
+ def api_key=(value)
66
+ warn "[DEPRECATION] `api_key=` is deprecated. Use `email = { api_key: '…' }` instead. Will be removed in 1.0.0"
67
+
68
+ @email[:api_key] = value
43
69
  end
44
70
 
45
71
  private
@@ -31,6 +31,21 @@ module Courrier
31
31
 
32
32
  def html = wrap(@html, with_layout: :html)
33
33
 
34
+ def to_h
35
+ {
36
+ from: @from,
37
+ to: @to,
38
+ reply_to: @reply_to,
39
+ cc: @cc,
40
+ bcc: @bcc,
41
+ subject: @subject,
42
+ text: @text,
43
+ html: @html,
44
+ auto_generate_text: @auto_generate_text,
45
+ layouts: @layouts
46
+ }
47
+ end
48
+
34
49
  private
35
50
 
36
51
  def wrap(content, with_layout:)