courrier 0.5.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 +7 -0
  2. data/Gemfile +15 -0
  3. data/Gemfile.lock +109 -0
  4. data/README.md +243 -0
  5. data/Rakefile +9 -0
  6. data/bin/console +11 -0
  7. data/bin/release +19 -0
  8. data/bin/setup +8 -0
  9. data/courrier.gemspec +25 -0
  10. data/lib/courrier/configuration/preview.rb +23 -0
  11. data/lib/courrier/configuration/providers.rb +41 -0
  12. data/lib/courrier/configuration.rb +53 -0
  13. data/lib/courrier/email/address.rb +37 -0
  14. data/lib/courrier/email/layouts.rb +40 -0
  15. data/lib/courrier/email/options.rb +55 -0
  16. data/lib/courrier/email/provider.rb +68 -0
  17. data/lib/courrier/email/providers/base.rb +39 -0
  18. data/lib/courrier/email/providers/logger.rb +41 -0
  19. data/lib/courrier/email/providers/loops.rb +36 -0
  20. data/lib/courrier/email/providers/mailgun.rb +36 -0
  21. data/lib/courrier/email/providers/mailjet.rb +50 -0
  22. data/lib/courrier/email/providers/mailpace.rb +32 -0
  23. data/lib/courrier/email/providers/postmark.rb +34 -0
  24. data/lib/courrier/email/providers/preview/default.html.erb +119 -0
  25. data/lib/courrier/email/providers/preview.rb +51 -0
  26. data/lib/courrier/email/providers/sendgrid.rb +57 -0
  27. data/lib/courrier/email/providers/sparkpost.rb +38 -0
  28. data/lib/courrier/email/request.rb +73 -0
  29. data/lib/courrier/email/result.rb +43 -0
  30. data/lib/courrier/email/transformer.rb +46 -0
  31. data/lib/courrier/email.rb +97 -0
  32. data/lib/courrier/errors.rb +11 -0
  33. data/lib/courrier/railtie.rb +23 -0
  34. data/lib/courrier/tasks/courrier.rake +13 -0
  35. data/lib/courrier/version.rb +3 -0
  36. data/lib/courrier.rb +10 -0
  37. data/lib/generators/courrier/email_generator.rb +19 -0
  38. data/lib/generators/courrier/install_generator.rb +11 -0
  39. data/lib/generators/courrier/templates/email.rb.tt +15 -0
  40. data/lib/generators/courrier/templates/initializer.rb.tt +38 -0
  41. metadata +125 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 394bb78e24569d93855f2bcf788662ec8773371779b7743c5737867b893d4b38
4
+ data.tar.gz: 4f35baf4f3ccca75ac05cd6bc7140f2eb4585c0c95e528f1aa45bc1227ec3777
5
+ SHA512:
6
+ metadata.gz: 387e9a879abac10ecbd97ac1a254fb08c40e48e8faf1a37f3a284dd2efd118dd70e0bf1d0032d3318914b2ddaa9242a56495547c6599dc3483844b3449114846
7
+ data.tar.gz: f5b458d0cc5ff6f640f0e3ffc19be8e0e6982721dcd4ff29a3dc49d42e7a3d6e9e6b0ba2d132e8f75d2a6c5edb8f6d2ae581b3076027fc9a5a48207c54ecc2ec
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
6
+
7
+ group :development do
8
+ gem "standard", "~> 1.49"
9
+ end
10
+
11
+ group :development, :test do
12
+ gem "rake", "~> 13.2", ">= 13.2.1"
13
+ gem "minitest", "~> 5.25", ">= 5.25.5"
14
+ gem "debug", "~> 1.9", ">= 1.9.2"
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,109 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ courrier (0.5.0)
5
+ launchy (>= 3.1, < 4)
6
+ nokogiri (>= 1.18, < 2)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ addressable (2.8.7)
12
+ public_suffix (>= 2.0.2, < 7.0)
13
+ ast (2.4.3)
14
+ childprocess (5.1.0)
15
+ logger (~> 1.5)
16
+ date (3.4.1)
17
+ debug (1.10.0)
18
+ irb (~> 1.10)
19
+ reline (>= 0.3.8)
20
+ io-console (0.8.0)
21
+ irb (1.15.2)
22
+ pp (>= 0.6.0)
23
+ rdoc (>= 4.0.0)
24
+ reline (>= 0.4.2)
25
+ json (2.11.1)
26
+ 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
+ lint_roller (1.1.0)
32
+ logger (1.7.0)
33
+ minitest (5.25.5)
34
+ nokogiri (1.18.8-arm64-darwin)
35
+ racc (~> 1.4)
36
+ nokogiri (1.18.8-x86_64-darwin)
37
+ racc (~> 1.4)
38
+ nokogiri (1.18.8-x86_64-linux-gnu)
39
+ racc (~> 1.4)
40
+ parallel (1.27.0)
41
+ parser (3.3.8.0)
42
+ ast (~> 2.4.1)
43
+ racc
44
+ pp (0.6.2)
45
+ prettyprint
46
+ prettyprint (0.2.0)
47
+ prism (1.4.0)
48
+ psych (5.2.3)
49
+ date
50
+ stringio
51
+ public_suffix (6.0.2)
52
+ racc (1.8.1)
53
+ rainbow (3.1.1)
54
+ rake (13.2.1)
55
+ rdoc (6.13.1)
56
+ psych (>= 4.0.0)
57
+ regexp_parser (2.10.0)
58
+ reline (0.6.1)
59
+ io-console (~> 0.5)
60
+ rubocop (1.75.3)
61
+ json (~> 2.3)
62
+ language_server-protocol (~> 3.17.0.2)
63
+ lint_roller (~> 1.1.0)
64
+ parallel (~> 1.10)
65
+ parser (>= 3.3.0.2)
66
+ rainbow (>= 2.2.2, < 4.0)
67
+ regexp_parser (>= 2.9.3, < 3.0)
68
+ rubocop-ast (>= 1.44.0, < 2.0)
69
+ ruby-progressbar (~> 1.7)
70
+ unicode-display_width (>= 2.4.0, < 4.0)
71
+ rubocop-ast (1.44.1)
72
+ parser (>= 3.3.7.2)
73
+ prism (~> 1.4)
74
+ rubocop-performance (1.25.0)
75
+ lint_roller (~> 1.1)
76
+ rubocop (>= 1.75.0, < 2.0)
77
+ rubocop-ast (>= 1.38.0, < 2.0)
78
+ ruby-progressbar (1.13.0)
79
+ standard (1.49.0)
80
+ language_server-protocol (~> 3.17.0.2)
81
+ lint_roller (~> 1.0)
82
+ rubocop (~> 1.75.2)
83
+ standard-custom (~> 1.0.0)
84
+ standard-performance (~> 1.8)
85
+ standard-custom (1.0.2)
86
+ lint_roller (~> 1.0)
87
+ rubocop (~> 1.50)
88
+ standard-performance (1.8.0)
89
+ lint_roller (~> 1.1)
90
+ rubocop-performance (~> 1.25.0)
91
+ stringio (3.1.7)
92
+ unicode-display_width (3.1.4)
93
+ unicode-emoji (~> 4.0, >= 4.0.4)
94
+ unicode-emoji (4.0.4)
95
+
96
+ PLATFORMS
97
+ arm64-darwin-23
98
+ x86_64-darwin-23
99
+ x86_64-linux
100
+
101
+ DEPENDENCIES
102
+ courrier!
103
+ debug (~> 1.9, >= 1.9.2)
104
+ minitest (~> 5.25, >= 5.25.5)
105
+ rake (~> 13.2, >= 13.2.1)
106
+ standard (~> 1.49)
107
+
108
+ BUNDLED WITH
109
+ 2.6.8
data/README.md ADDED
@@ -0,0 +1,243 @@
1
+ # Courrier
2
+
3
+ Modern, API-powered email delivery for Ruby apps.
4
+
5
+ ```ruby
6
+ # Quick example
7
+ OrderEmail.deliver to: "recipient@railsdesigner.com"
8
+ ```
9
+
10
+ <a href="https://railsdesigner.com/" target="_blank">
11
+ <picture>
12
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Rails-Designer/courrier/HEAD/.github/logo-dark.svg">
13
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/Rails-Designer/courrier/HEAD/.github/logo-light.svg">
14
+ <img alt="Rails Designer logo" src="https://raw.githubusercontent.com/Rails-Designer/courrier/HEAD/.github/logo-light.svg" width="240" style="max-width: 100%;">
15
+ </picture>
16
+ </a>
17
+
18
+ **Sponsored By [Rails Designer](https://railsdesigner.com/)**
19
+
20
+
21
+ ## Installation
22
+
23
+ Add the gem:
24
+ ```bash
25
+ bundle add courrier
26
+ ```
27
+
28
+ Generate the configuration file:
29
+ ```bash
30
+ bin/rails generate courrier:install
31
+ ```
32
+
33
+ This creates `config/initializers/courrier.rb` for configuring email providers and default settings.
34
+
35
+
36
+ ## Usage
37
+
38
+ Generate a new email:
39
+ ```bash
40
+ bin/rails generate courrier:email Order
41
+ ```
42
+ ```ruby
43
+ class OrderEmail < Courrier::Email
44
+ def subject = "Here is your order!"
45
+
46
+ def text
47
+ <<~TEXT
48
+ text body here
49
+ TEXT
50
+ end
51
+
52
+ def html
53
+ <<~HTML
54
+ html body here
55
+ HTML
56
+ end
57
+ end
58
+ ```
59
+ 💡 Write your email content using the [Minimal Email Editor](https://railsdesigner.com/minimal-email-editor/).
60
+
61
+
62
+ ## Configuration
63
+
64
+ Courrier uses a configuration system with three levels (from lowest to highest priority):
65
+
66
+ 1. **Global configuration**
67
+ ```ruby
68
+ Courrier.configure do |config|
69
+ config.provider = "postmark"
70
+ config.api_key = "xyz"
71
+ config.from = "devs@railsdesigner.com"
72
+ config.default_url_options = { host: "railsdesigner.com" }
73
+
74
+ # Provider-specific configuration
75
+ config.providers.loops.transactional_id = "default-template"
76
+ config.providers.mailgun.domain = "notifications.railsdesigner.com"
77
+ end
78
+ ```
79
+
80
+ 2. **Email class defaults**
81
+ ```ruby
82
+ class OrderEmail < Courrier::Email
83
+ configure from: "devs@railsdesigner.com",
84
+ cc: "records@railsdesigner.com",
85
+ provider: "mailgun",
86
+ end
87
+ ```
88
+
89
+ 3. **Instance options**
90
+ ```ruby
91
+ OrderEmail.deliver to: "recipient@railsdesigner.com",\
92
+ from: "devs@railsdesigner.com",\
93
+ provider: "sendgrid",\
94
+ api_key: "sk_a1b1c3"
95
+ ```
96
+
97
+
98
+ ## Providers
99
+
100
+ Courrier supports these transactional email providers:
101
+
102
+ - [Loops](https://loops.so)
103
+ - [Mailgun](https://mailgun.com)
104
+ - [Mailjet](https://mailjet.com)
105
+ - [MailPace](https://mailpace.com)
106
+ - [Postmark](https://postmarkapp.com)
107
+ - [SendGrid](https://sendgrid.com)
108
+ - [SparkPost](https://sparkpost.com)
109
+
110
+ ⚠️ 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). 🙏
111
+
112
+
113
+ ## More Features
114
+
115
+ Additional functionality to help with development and email handling:
116
+
117
+
118
+ ### Email Preview
119
+
120
+ Preview emails in your browser during development:
121
+ ```ruby
122
+ 
config.provider = "preview" # Opens emails in your default browser
123
+ ```
124
+
125
+ 
Previews are automatically cleared with `bin/rails tmp:clear`, or manually with `bin/rails courrier:clear`.
126
+
127
+
128
+ ### Layout Support
129
+
130
+ Wrap your email content using layouts:
131
+ ```ruby
132
+ class OrderEmail < Courrier::Email
133
+ layout text: "%{content}\n\nThanks for your order!",
134
+ html: "<div>\n%{content}\n</div>"
135
+ end
136
+ ```
137
+
138
+ Using a method:
139
+ ```ruby
140
+ class OrderEmail < Courrier::Email
141
+ layout html: :html_layout
142
+
143
+ def html_layout
144
+ <<~HTML
145
+ <div style='font-family: ui-sans-serif, system-ui;'>
146
+ %{content}
147
+ </div>
148
+ HTML
149
+ end
150
+ end
151
+ ```
152
+
153
+ Using a separate class:
154
+ ```ruby
155
+ class OrderEmail < Courrier::Email
156
+ layout html: OrderLayout
157
+ end
158
+
159
+ class OrderLayout
160
+ self.call
161
+ <<~HTML
162
+ <div style='font-family: ui-sans-serif, system-ui;'>
163
+ %{content}
164
+ </div>
165
+ HTML
166
+ end
167
+ end
168
+ ```
169
+
170
+
171
+ ### Auto-generate Text from HTML
172
+
173
+ Automatically generate plain text versions from your HTML emails:
174
+ ```ruby
175
+ 
config.auto_generate_text = true # Defaults to false
176
+ ```
177
+
178
+
179
+ ### Email Address Helper
180
+
181
+ Compose RFC 2822-compliant email addresses with display names:
182
+ ```ruby
183
+ class SignupsController < ApplicationController
184
+ def create
185
+ recipient = email_with_name("devs@railsdesigner.com", "Rails Designer Devs")
186
+
187
+ WelcomeEmail.deliver to: recipient
188
+ end
189
+ end
190
+ ```
191
+
192
+ In Plain Ruby Objects:
193
+ ```ruby
194
+ class Signup
195
+ include Courrier::Email::Address
196
+
197
+ def send_welcome_email(user)
198
+ recipient = email_with_name(user.email_address, user.name)
199
+
200
+ WelcomeEmail.deliver to: recipient
201
+ end
202
+ end
203
+ ```
204
+
205
+
206
+ ### Logger Provider
207
+
208
+ Use Ruby's built-in Logger for development and testing:
209
+
210
+ ```ruby
211
+ config.provider = "logger" # Outputs emails to STDOUT
212
+ config.logger = custom_logger # Optional: defaults to ::Logger.new($stdout)
213
+ ```
214
+
215
+ ### Custom Providers
216
+
217
+ Create your own provider by inheriting from `Courrier::Email::Base`:
218
+ ```ruby
219
+ class CustomProvider < Courrier::Email::Base
220
+ ENDPOINT_URL = ""
221
+
222
+ def body = ""
223
+
224
+ def headers = ""
225
+ end
226
+ ```
227
+
228
+ Then configure it:
229
+ ```ruby
230
+ config.provider = "CustomProvider"
231
+ ```
232
+
233
+ Check the [existing providers](https://github.com/Rails-Designer/courrier/tree/main/lib/courrier/email/providers) for implementation examples.
234
+
235
+
236
+ ## Contributing
237
+
238
+ This project uses [Standard](https://github.com/testdouble/standard) for formatting Ruby code. Please make sure to run `rake` before submitting pull requests.
239
+
240
+
241
+ ## License
242
+
243
+ Courrier is released under the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+ require "standard/rake"
6
+
7
+ Minitest::TestTask.create
8
+
9
+ task default: %i[test standard]
data/bin/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "courrier"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ require "irb"
11
+ IRB.start(__FILE__)
data/bin/release ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+
3
+ VERSION=$1
4
+
5
+ if [ -z "$VERSION" ]; then
6
+ echo "Error: The version number is required."
7
+ echo "Usage: $0 <version-number>"
8
+ exit 1
9
+ fi
10
+
11
+ printf "module Courrier\n VERSION = \"$VERSION\"\nend\n" > ./lib/courrier/version.rb
12
+ bundle
13
+ git add Gemfile.lock lib/courrier/version.rb
14
+ git commit -m "Bump version for $VERSION"
15
+ git push
16
+ git tag v$VERSION
17
+ git push --tags
18
+ gem build courrier.gemspec
19
+ gem push "courrier-$VERSION.gem"
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/courrier.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/courrier/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "courrier"
7
+ spec.version = Courrier::VERSION
8
+ spec.authors = ["Rails Designer"]
9
+ spec.email = ["devs@railsdesigner.com"]
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."
13
+ spec.homepage = "https://railsdesigner.com/courrier/"
14
+ spec.license = "MIT"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/Rails-Designer/courrier/"
18
+
19
+ spec.files = Dir["{bin,app,config,db,lib,public}/**/*", "Rakefile", "README.md", "courrier.gemspec", "Gemfile", "Gemfile.lock"]
20
+
21
+ spec.required_ruby_version = ">= 3.2.0"
22
+
23
+ spec.add_dependency "launchy", ">= 3.1", "< 4"
24
+ spec.add_dependency "nokogiri", ">= 1.18", "< 2"
25
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Courrier
4
+ class Configuration
5
+ class Preview
6
+ attr_accessor :destination, :auto_open, :template_path
7
+
8
+ def initialize
9
+ @destination = default_destination
10
+ @auto_open = true
11
+ @template_path = File.expand_path("../../../courrier/email/providers/preview/default.html.erb", __FILE__)
12
+ end
13
+
14
+ private
15
+
16
+ def default_destination
17
+ return Rails.root.join("tmp", "courrier", "emails").to_s if defined?(Rails)
18
+
19
+ File.join(Dir.tmpdir, "courrier", "emails")
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Courrier
4
+ class Configuration
5
+ class Providers
6
+ def initialize
7
+ @providers = {}
8
+ end
9
+
10
+ def method_missing(name, *, **)
11
+ @providers[name.to_sym] ||= ProviderConfig.new
12
+ end
13
+
14
+ def respond_to_missing?(name, include_private = false) = true
15
+
16
+ def [](provider_name)
17
+ @providers[provider_name.to_sym] ||= ProviderConfig.new
18
+ end
19
+
20
+ def to_h = @providers.transform_values(&:to_h)
21
+ end
22
+
23
+ class ProviderConfig
24
+ def initialize
25
+ @options = {}
26
+ end
27
+
28
+ def method_missing(name, value = nil, **)
29
+ option_name = name.to_s.chomp("=").to_sym
30
+
31
+ return @options[option_name] = value if name.to_s.end_with?("=")
32
+
33
+ @options[name.to_sym]
34
+ end
35
+
36
+ def respond_to_missing?(name, include_private = false) = true
37
+
38
+ def to_h = @options
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "courrier/configuration/preview"
4
+ require "courrier/configuration/providers"
5
+
6
+ module Courrier
7
+ class << self
8
+ attr_writer :configuration
9
+
10
+ def configure
11
+ self.configuration ||= Configuration.new
12
+
13
+ yield(configuration) if block_given?
14
+ end
15
+
16
+ def configuration
17
+ @configuration ||= Configuration.new
18
+ end
19
+ end
20
+
21
+ class Configuration
22
+ attr_accessor :provider, :api_key, :logger, :email_path, :layouts, :default_url_options, :auto_generate_text,
23
+ :from, :reply_to, :cc, :bcc
24
+ attr_reader :providers, :preview
25
+
26
+ def initialize
27
+ @provider = "logger"
28
+ @api_key = nil
29
+ @logger = ::Logger.new($stdout)
30
+ @email_path = default_email_path
31
+
32
+ @layouts = nil
33
+ @default_url_options = {host: ""}
34
+ @auto_generate_text = false
35
+
36
+ @from = nil
37
+ @reply_to = nil
38
+ @cc = nil
39
+ @bcc = nil
40
+
41
+ @providers = Courrier::Configuration::Providers.new
42
+ @preview = Courrier::Configuration::Preview.new
43
+ end
44
+
45
+ private
46
+
47
+ def default_email_path
48
+ return Rails.root.join("app", "emails").to_s if defined?(Rails)
49
+
50
+ File.join("courrier", "emails")
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Courrier
4
+ class Email
5
+ module Address
6
+ class << self
7
+ def with_name(address, name)
8
+ raise Courrier::ArgumentError, "Both `address` and `name` are required" if address.nil? || name.nil?
9
+ raise Courrier::ArgumentError, "Both `address` and `name` must not be empty" if address.empty? || name.empty?
10
+
11
+ address = address.gsub(/[<>]/, "")
12
+ formatted_name = format_display_for(name)
13
+
14
+ "#{formatted_name} <#{address}>"
15
+ end
16
+
17
+ private
18
+
19
+ def format_display_for(name)
20
+ return quote_escaped(name) if special_characters_in?(name)
21
+
22
+ name
23
+ end
24
+
25
+ def quote_escaped(name) = %("#{name.gsub('"', '\\"')}")
26
+
27
+ def special_characters_in?(name)
28
+ name =~ /[(),.:;<>@\[\]"]/
29
+ end
30
+ end
31
+
32
+ def email_with_name(email, name) = Address.with_name(email, name)
33
+ alias_method :email_address_with_name, :email_with_name
34
+ module_function :email_with_name, :email_address_with_name
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Courrier
4
+ class Email
5
+ class Layouts
6
+ def initialize(email)
7
+ @email = email
8
+ end
9
+
10
+ def build
11
+ return [] if no_layouts?
12
+
13
+ [layouts]
14
+ end
15
+
16
+ private
17
+
18
+ FORMATS = %w[html text]
19
+
20
+ def no_layouts? = @email.class.layouts.nil?
21
+
22
+ def layouts
23
+ FORMATS.map(&:to_sym).to_h do |format|
24
+ template = @email.class.layouts[format]
25
+
26
+ next if template.nil?
27
+
28
+ [format, render(template)]
29
+ end
30
+ end
31
+
32
+ def render(template)
33
+ return @email.send(template) if template.is_a?(Symbol)
34
+ return template.call if template.is_a?(Class)
35
+
36
+ template
37
+ end
38
+ end
39
+ end
40
+ end