actionmailer 5.2.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionmailer might be problematic. Click here for more details.

@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 36b5125296024008db8a3fa813beabfe9b12191a187d0309b600026678ec0994
4
+ data.tar.gz: f7af87aee1d59fed6d65023b5465cc50b6a6901983fcdcd004fd9c4654b46fa6
5
+ SHA512:
6
+ metadata.gz: 48cd75ea744601d397d531977028be784c236e7d6e9d6e308f36e1bfd29db4eda440bce2ea986f3528aaddeb7c1e87fe4c92bc2a1dcb5a77492034e97d9db733
7
+ data.tar.gz: c7e73a5a3ee865e914e02c82c1f219e940fd013e32418d3c6fc2977cec8f59e902928dfe76eff3b0dfd6af7a7aa16b4fe093a01334d52c9268e195ccb2ce5678
@@ -0,0 +1,54 @@
1
+ ## Rails 5.2.3 (March 27, 2019) ##
2
+
3
+ * No changes.
4
+
5
+
6
+ ## Rails 5.2.2.1 (March 11, 2019) ##
7
+
8
+ * No changes.
9
+
10
+
11
+ ## Rails 5.2.2 (December 04, 2018) ##
12
+
13
+ * No changes.
14
+
15
+
16
+ ## Rails 5.2.1.1 (November 27, 2018) ##
17
+
18
+ * No changes.
19
+
20
+
21
+ ## Rails 5.2.1 (August 07, 2018) ##
22
+
23
+ * Ensure mail gem is eager autoloaded when eager load is true to prevent thread deadlocks.
24
+
25
+ *Samuel Cochran*
26
+
27
+
28
+ ## Rails 5.2.0 (April 09, 2018) ##
29
+
30
+ * Bring back proc with arity of 1 in `ActionMailer::Base.default` proc
31
+ since it was supported in Rails 5.0 but not deprecated.
32
+
33
+ *Jimmy Bourassa*
34
+
35
+ * Add `assert_enqueued_email_with` test helper.
36
+
37
+ assert_enqueued_email_with ContactMailer, :welcome do
38
+ ContactMailer.welcome.deliver_later
39
+ end
40
+
41
+ *Mikkel Malmberg*
42
+
43
+ * Allow Action Mailer classes to configure their delivery job.
44
+
45
+ class MyMailer < ApplicationMailer
46
+ self.delivery_job = MyCustomDeliveryJob
47
+
48
+ ...
49
+ end
50
+
51
+ *Matthew Mongeau*
52
+
53
+
54
+ Please check [5-1-stable](https://github.com/rails/rails/blob/5-1-stable/actionmailer/CHANGELOG.md) for previous changes.
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2004-2018 David Heinemeier Hansson
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
@@ -0,0 +1,175 @@
1
+ = Action Mailer -- Easy email delivery and testing
2
+
3
+ Action Mailer is a framework for designing email service layers. These layers
4
+ are used to consolidate code for sending out forgotten passwords, welcome
5
+ wishes on signup, invoices for billing, and any other use case that requires
6
+ a written notification to either a person or another system.
7
+
8
+ Action Mailer is in essence a wrapper around Action Controller and the
9
+ Mail gem. It provides a way to make emails using templates in the same
10
+ way that Action Controller renders views using templates.
11
+
12
+ Additionally, an Action Mailer class can be used to process incoming email,
13
+ such as allowing a blog to accept new posts from an email (which could even
14
+ have been sent from a phone).
15
+
16
+ == Sending emails
17
+
18
+ The framework works by initializing any instance variables you want to be
19
+ available in the email template, followed by a call to +mail+ to deliver
20
+ the email.
21
+
22
+ This can be as simple as:
23
+
24
+ class Notifier < ActionMailer::Base
25
+ default from: 'system@loudthinking.com'
26
+
27
+ def welcome(recipient)
28
+ @recipient = recipient
29
+ mail(to: recipient,
30
+ subject: "[Signed up] Welcome #{recipient}")
31
+ end
32
+ end
33
+
34
+ The body of the email is created by using an Action View template (regular
35
+ ERB) that has the instance variables that are declared in the mailer action.
36
+
37
+ So the corresponding body template for the method above could look like this:
38
+
39
+ Hello there,
40
+
41
+ Mr. <%= @recipient %>
42
+
43
+ Thank you for signing up!
44
+
45
+ If the recipient was given as "david@loudthinking.com", the email
46
+ generated would look like this:
47
+
48
+ Date: Mon, 25 Jan 2010 22:48:09 +1100
49
+ From: system@loudthinking.com
50
+ To: david@loudthinking.com
51
+ Message-ID: <4b5d84f9dd6a5_7380800b81ac29578@void.loudthinking.com.mail>
52
+ Subject: [Signed up] Welcome david@loudthinking.com
53
+ Mime-Version: 1.0
54
+ Content-Type: text/plain;
55
+ charset="US-ASCII";
56
+ Content-Transfer-Encoding: 7bit
57
+
58
+ Hello there,
59
+
60
+ Mr. david@loudthinking.com
61
+
62
+ Thank you for signing up!
63
+
64
+ In order to send mails, you simply call the method and then call +deliver_now+ on the return value.
65
+
66
+ Calling the method returns a Mail Message object:
67
+
68
+ message = Notifier.welcome("david@loudthinking.com") # => Returns a Mail::Message object
69
+ message.deliver_now # => delivers the email
70
+
71
+ Or you can just chain the methods together like:
72
+
73
+ Notifier.welcome("david@loudthinking.com").deliver_now # Creates the email and sends it immediately
74
+
75
+ == Setting defaults
76
+
77
+ It is possible to set default values that will be used in every method in your
78
+ Action Mailer class. To implement this functionality, you just call the public
79
+ class method +default+ which you get for free from <tt>ActionMailer::Base</tt>.
80
+ This method accepts a Hash as the parameter. You can use any of the headers,
81
+ email messages have, like +:from+ as the key. You can also pass in a string as
82
+ the key, like "Content-Type", but Action Mailer does this out of the box for you,
83
+ so you won't need to worry about that. Finally, it is also possible to pass in a
84
+ Proc that will get evaluated when it is needed.
85
+
86
+ Note that every value you set with this method will get overwritten if you use the
87
+ same key in your mailer method.
88
+
89
+ Example:
90
+
91
+ class AuthenticationMailer < ActionMailer::Base
92
+ default from: "awesome@application.com", subject: Proc.new { "E-mail was generated at #{Time.now}" }
93
+ .....
94
+ end
95
+
96
+ == Receiving emails
97
+
98
+ To receive emails, you need to implement a public instance method called
99
+ +receive+ that takes an email object as its single parameter. The Action Mailer
100
+ framework has a corresponding class method, which is also called +receive+, that
101
+ accepts a raw, unprocessed email as a string, which it then turns into the email
102
+ object and calls the receive instance method.
103
+
104
+ Example:
105
+
106
+ class Mailman < ActionMailer::Base
107
+ def receive(email)
108
+ page = Page.find_by(address: email.to.first)
109
+ page.emails.create(
110
+ subject: email.subject, body: email.body
111
+ )
112
+
113
+ if email.has_attachments?
114
+ email.attachments.each do |attachment|
115
+ page.attachments.create({
116
+ file: attachment, description: email.subject
117
+ })
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ This Mailman can be the target for Postfix or other MTAs. In Rails, you would use
124
+ the runner in the trivial case like this:
125
+
126
+ rails runner 'Mailman.receive(STDIN.read)'
127
+
128
+ However, invoking Rails in the runner for each mail to be received is very
129
+ resource intensive. A single instance of Rails should be run within a daemon, if
130
+ it is going to process more than just a limited amount of email.
131
+
132
+ == Configuration
133
+
134
+ The Base class has the full list of configuration options. Here's an example:
135
+
136
+ ActionMailer::Base.smtp_settings = {
137
+ address: 'smtp.yourserver.com', # default: localhost
138
+ port: '25', # default: 25
139
+ user_name: 'user',
140
+ password: 'pass',
141
+ authentication: :plain # :plain, :login or :cram_md5
142
+ }
143
+
144
+
145
+ == Download and installation
146
+
147
+ The latest version of Action Mailer can be installed with RubyGems:
148
+
149
+ $ gem install actionmailer
150
+
151
+ Source code can be downloaded as part of the Rails project on GitHub:
152
+
153
+ * https://github.com/rails/rails/tree/5-2-stable/actionmailer
154
+
155
+
156
+ == License
157
+
158
+ Action Mailer is released under the MIT license:
159
+
160
+ * https://opensource.org/licenses/MIT
161
+
162
+
163
+ == Support
164
+
165
+ API documentation is at
166
+
167
+ * http://api.rubyonrails.org
168
+
169
+ Bug reports for the Ruby on Rails project can be filed here:
170
+
171
+ * https://github.com/rails/rails/issues
172
+
173
+ Feature requests should be discussed on the rails-core mailing list here:
174
+
175
+ * https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # Copyright (c) 2004-2018 David Heinemeier Hansson
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ #++
25
+
26
+ require "abstract_controller"
27
+ require "action_mailer/version"
28
+
29
+ # Common Active Support usage in Action Mailer
30
+ require "active_support"
31
+ require "active_support/rails"
32
+ require "active_support/core_ext/class"
33
+ require "active_support/core_ext/module/attr_internal"
34
+ require "active_support/core_ext/string/inflections"
35
+ require "active_support/lazy_load_hooks"
36
+
37
+ module ActionMailer
38
+ extend ::ActiveSupport::Autoload
39
+
40
+ eager_autoload do
41
+ autoload :Collector
42
+ end
43
+
44
+ autoload :Base
45
+ autoload :DeliveryMethods
46
+ autoload :InlinePreviewInterceptor
47
+ autoload :MailHelper
48
+ autoload :Parameterized
49
+ autoload :Preview
50
+ autoload :Previews, "action_mailer/preview"
51
+ autoload :TestCase
52
+ autoload :TestHelper
53
+ autoload :MessageDelivery
54
+ autoload :DeliveryJob
55
+
56
+ def self.eager_load!
57
+ super
58
+
59
+ require "mail"
60
+ Mail.eager_autoload!
61
+ end
62
+ end
63
+
64
+ autoload :Mime, "action_dispatch/http/mime_type"
65
+
66
+ ActiveSupport.on_load(:action_view) do
67
+ ActionView::Base.default_formats ||= Mime::SET.symbols
68
+ ActionView::Template::Types.delegate_to Mime
69
+ end
@@ -0,0 +1,991 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mail"
4
+ require "action_mailer/collector"
5
+ require "active_support/core_ext/string/inflections"
6
+ require "active_support/core_ext/hash/except"
7
+ require "active_support/core_ext/module/anonymous"
8
+
9
+ require "action_mailer/log_subscriber"
10
+ require "action_mailer/rescuable"
11
+
12
+ module ActionMailer
13
+ # Action Mailer allows you to send email from your application using a mailer model and views.
14
+ #
15
+ # = Mailer Models
16
+ #
17
+ # To use Action Mailer, you need to create a mailer model.
18
+ #
19
+ # $ rails generate mailer Notifier
20
+ #
21
+ # The generated model inherits from <tt>ApplicationMailer</tt> which in turn
22
+ # inherits from <tt>ActionMailer::Base</tt>. A mailer model defines methods
23
+ # used to generate an email message. In these methods, you can setup variables to be used in
24
+ # the mailer views, options on the mail itself such as the <tt>:from</tt> address, and attachments.
25
+ #
26
+ # class ApplicationMailer < ActionMailer::Base
27
+ # default from: 'from@example.com'
28
+ # layout 'mailer'
29
+ # end
30
+ #
31
+ # class NotifierMailer < ApplicationMailer
32
+ # default from: 'no-reply@example.com',
33
+ # return_path: 'system@example.com'
34
+ #
35
+ # def welcome(recipient)
36
+ # @account = recipient
37
+ # mail(to: recipient.email_address_with_name,
38
+ # bcc: ["bcc@example.com", "Order Watcher <watcher@example.com>"])
39
+ # end
40
+ # end
41
+ #
42
+ # Within the mailer method, you have access to the following methods:
43
+ #
44
+ # * <tt>attachments[]=</tt> - Allows you to add attachments to your email in an intuitive
45
+ # manner; <tt>attachments['filename.png'] = File.read('path/to/filename.png')</tt>
46
+ #
47
+ # * <tt>attachments.inline[]=</tt> - Allows you to add an inline attachment to your email
48
+ # in the same manner as <tt>attachments[]=</tt>
49
+ #
50
+ # * <tt>headers[]=</tt> - Allows you to specify any header field in your email such
51
+ # as <tt>headers['X-No-Spam'] = 'True'</tt>. Note that declaring a header multiple times
52
+ # will add many fields of the same name. Read #headers doc for more information.
53
+ #
54
+ # * <tt>headers(hash)</tt> - Allows you to specify multiple headers in your email such
55
+ # as <tt>headers({'X-No-Spam' => 'True', 'In-Reply-To' => '1234@message.id'})</tt>
56
+ #
57
+ # * <tt>mail</tt> - Allows you to specify email to be sent.
58
+ #
59
+ # The hash passed to the mail method allows you to specify any header that a <tt>Mail::Message</tt>
60
+ # will accept (any valid email header including optional fields).
61
+ #
62
+ # The +mail+ method, if not passed a block, will inspect your views and send all the views with
63
+ # the same name as the method, so the above action would send the +welcome.text.erb+ view
64
+ # file as well as the +welcome.html.erb+ view file in a +multipart/alternative+ email.
65
+ #
66
+ # If you want to explicitly render only certain templates, pass a block:
67
+ #
68
+ # mail(to: user.email) do |format|
69
+ # format.text
70
+ # format.html
71
+ # end
72
+ #
73
+ # The block syntax is also useful in providing information specific to a part:
74
+ #
75
+ # mail(to: user.email) do |format|
76
+ # format.text(content_transfer_encoding: "base64")
77
+ # format.html
78
+ # end
79
+ #
80
+ # Or even to render a special view:
81
+ #
82
+ # mail(to: user.email) do |format|
83
+ # format.text
84
+ # format.html { render "some_other_template" }
85
+ # end
86
+ #
87
+ # = Mailer views
88
+ #
89
+ # Like Action Controller, each mailer class has a corresponding view directory in which each
90
+ # method of the class looks for a template with its name.
91
+ #
92
+ # To define a template to be used with a mailer, create an <tt>.erb</tt> file with the same
93
+ # name as the method in your mailer model. For example, in the mailer defined above, the template at
94
+ # <tt>app/views/notifier_mailer/welcome.text.erb</tt> would be used to generate the email.
95
+ #
96
+ # Variables defined in the methods of your mailer model are accessible as instance variables in their
97
+ # corresponding view.
98
+ #
99
+ # Emails by default are sent in plain text, so a sample view for our model example might look like this:
100
+ #
101
+ # Hi <%= @account.name %>,
102
+ # Thanks for joining our service! Please check back often.
103
+ #
104
+ # You can even use Action View helpers in these views. For example:
105
+ #
106
+ # You got a new note!
107
+ # <%= truncate(@note.body, length: 25) %>
108
+ #
109
+ # If you need to access the subject, from or the recipients in the view, you can do that through message object:
110
+ #
111
+ # You got a new note from <%= message.from %>!
112
+ # <%= truncate(@note.body, length: 25) %>
113
+ #
114
+ #
115
+ # = Generating URLs
116
+ #
117
+ # URLs can be generated in mailer views using <tt>url_for</tt> or named routes. Unlike controllers from
118
+ # Action Pack, the mailer instance doesn't have any context about the incoming request, so you'll need
119
+ # to provide all of the details needed to generate a URL.
120
+ #
121
+ # When using <tt>url_for</tt> you'll need to provide the <tt>:host</tt>, <tt>:controller</tt>, and <tt>:action</tt>:
122
+ #
123
+ # <%= url_for(host: "example.com", controller: "welcome", action: "greeting") %>
124
+ #
125
+ # When using named routes you only need to supply the <tt>:host</tt>:
126
+ #
127
+ # <%= users_url(host: "example.com") %>
128
+ #
129
+ # You should use the <tt>named_route_url</tt> style (which generates absolute URLs) and avoid using the
130
+ # <tt>named_route_path</tt> style (which generates relative URLs), since clients reading the mail will
131
+ # have no concept of a current URL from which to determine a relative path.
132
+ #
133
+ # It is also possible to set a default host that will be used in all mailers by setting the <tt>:host</tt>
134
+ # option as a configuration option in <tt>config/application.rb</tt>:
135
+ #
136
+ # config.action_mailer.default_url_options = { host: "example.com" }
137
+ #
138
+ # You can also define a <tt>default_url_options</tt> method on individual mailers to override these
139
+ # default settings per-mailer.
140
+ #
141
+ # By default when <tt>config.force_ssl</tt> is +true+, URLs generated for hosts will use the HTTPS protocol.
142
+ #
143
+ # = Sending mail
144
+ #
145
+ # Once a mailer action and template are defined, you can deliver your message or defer its creation and
146
+ # delivery for later:
147
+ #
148
+ # NotifierMailer.welcome(User.first).deliver_now # sends the email
149
+ # mail = NotifierMailer.welcome(User.first) # => an ActionMailer::MessageDelivery object
150
+ # mail.deliver_now # generates and sends the email now
151
+ #
152
+ # The <tt>ActionMailer::MessageDelivery</tt> class is a wrapper around a delegate that will call
153
+ # your method to generate the mail. If you want direct access to the delegator, or <tt>Mail::Message</tt>,
154
+ # you can call the <tt>message</tt> method on the <tt>ActionMailer::MessageDelivery</tt> object.
155
+ #
156
+ # NotifierMailer.welcome(User.first).message # => a Mail::Message object
157
+ #
158
+ # Action Mailer is nicely integrated with Active Job so you can generate and send emails in the background
159
+ # (example: outside of the request-response cycle, so the user doesn't have to wait on it):
160
+ #
161
+ # NotifierMailer.welcome(User.first).deliver_later # enqueue the email sending to Active Job
162
+ #
163
+ # Note that <tt>deliver_later</tt> will execute your method from the background job.
164
+ #
165
+ # You never instantiate your mailer class. Rather, you just call the method you defined on the class itself.
166
+ # All instance methods are expected to return a message object to be sent.
167
+ #
168
+ # = Multipart Emails
169
+ #
170
+ # Multipart messages can also be used implicitly because Action Mailer will automatically detect and use
171
+ # multipart templates, where each template is named after the name of the action, followed by the content
172
+ # type. Each such detected template will be added to the message, as a separate part.
173
+ #
174
+ # For example, if the following templates exist:
175
+ # * signup_notification.text.erb
176
+ # * signup_notification.html.erb
177
+ # * signup_notification.xml.builder
178
+ # * signup_notification.yml.erb
179
+ #
180
+ # Each would be rendered and added as a separate part to the message, with the corresponding content
181
+ # type. The content type for the entire message is automatically set to <tt>multipart/alternative</tt>,
182
+ # which indicates that the email contains multiple different representations of the same email
183
+ # body. The same instance variables defined in the action are passed to all email templates.
184
+ #
185
+ # Implicit template rendering is not performed if any attachments or parts have been added to the email.
186
+ # This means that you'll have to manually add each part to the email and set the content type of the email
187
+ # to <tt>multipart/alternative</tt>.
188
+ #
189
+ # = Attachments
190
+ #
191
+ # Sending attachment in emails is easy:
192
+ #
193
+ # class NotifierMailer < ApplicationMailer
194
+ # def welcome(recipient)
195
+ # attachments['free_book.pdf'] = File.read('path/to/file.pdf')
196
+ # mail(to: recipient, subject: "New account information")
197
+ # end
198
+ # end
199
+ #
200
+ # Which will (if it had both a <tt>welcome.text.erb</tt> and <tt>welcome.html.erb</tt>
201
+ # template in the view directory), send a complete <tt>multipart/mixed</tt> email with two parts,
202
+ # the first part being a <tt>multipart/alternative</tt> with the text and HTML email parts inside,
203
+ # and the second being a <tt>application/pdf</tt> with a Base64 encoded copy of the file.pdf book
204
+ # with the filename +free_book.pdf+.
205
+ #
206
+ # If you need to send attachments with no content, you need to create an empty view for it,
207
+ # or add an empty body parameter like this:
208
+ #
209
+ # class NotifierMailer < ApplicationMailer
210
+ # def welcome(recipient)
211
+ # attachments['free_book.pdf'] = File.read('path/to/file.pdf')
212
+ # mail(to: recipient, subject: "New account information", body: "")
213
+ # end
214
+ # end
215
+ #
216
+ # You can also send attachments with html template, in this case you need to add body, attachments,
217
+ # and custom content type like this:
218
+ #
219
+ # class NotifierMailer < ApplicationMailer
220
+ # def welcome(recipient)
221
+ # attachments["free_book.pdf"] = File.read("path/to/file.pdf")
222
+ # mail(to: recipient,
223
+ # subject: "New account information",
224
+ # content_type: "text/html",
225
+ # body: "<html><body>Hello there</body></html>")
226
+ # end
227
+ # end
228
+ #
229
+ # = Inline Attachments
230
+ #
231
+ # You can also specify that a file should be displayed inline with other HTML. This is useful
232
+ # if you want to display a corporate logo or a photo.
233
+ #
234
+ # class NotifierMailer < ApplicationMailer
235
+ # def welcome(recipient)
236
+ # attachments.inline['photo.png'] = File.read('path/to/photo.png')
237
+ # mail(to: recipient, subject: "Here is what we look like")
238
+ # end
239
+ # end
240
+ #
241
+ # And then to reference the image in the view, you create a <tt>welcome.html.erb</tt> file and
242
+ # make a call to +image_tag+ passing in the attachment you want to display and then call
243
+ # +url+ on the attachment to get the relative content id path for the image source:
244
+ #
245
+ # <h1>Please Don't Cringe</h1>
246
+ #
247
+ # <%= image_tag attachments['photo.png'].url -%>
248
+ #
249
+ # As we are using Action View's +image_tag+ method, you can pass in any other options you want:
250
+ #
251
+ # <h1>Please Don't Cringe</h1>
252
+ #
253
+ # <%= image_tag attachments['photo.png'].url, alt: 'Our Photo', class: 'photo' -%>
254
+ #
255
+ # = Observing and Intercepting Mails
256
+ #
257
+ # Action Mailer provides hooks into the Mail observer and interceptor methods. These allow you to
258
+ # register classes that are called during the mail delivery life cycle.
259
+ #
260
+ # An observer class must implement the <tt>:delivered_email(message)</tt> method which will be
261
+ # called once for every email sent after the email has been sent.
262
+ #
263
+ # An interceptor class must implement the <tt>:delivering_email(message)</tt> method which will be
264
+ # called before the email is sent, allowing you to make modifications to the email before it hits
265
+ # the delivery agents. Your class should make any needed modifications directly to the passed
266
+ # in <tt>Mail::Message</tt> instance.
267
+ #
268
+ # = Default Hash
269
+ #
270
+ # Action Mailer provides some intelligent defaults for your emails, these are usually specified in a
271
+ # default method inside the class definition:
272
+ #
273
+ # class NotifierMailer < ApplicationMailer
274
+ # default sender: 'system@example.com'
275
+ # end
276
+ #
277
+ # You can pass in any header value that a <tt>Mail::Message</tt> accepts. Out of the box,
278
+ # <tt>ActionMailer::Base</tt> sets the following:
279
+ #
280
+ # * <tt>mime_version: "1.0"</tt>
281
+ # * <tt>charset: "UTF-8"</tt>
282
+ # * <tt>content_type: "text/plain"</tt>
283
+ # * <tt>parts_order: [ "text/plain", "text/enriched", "text/html" ]</tt>
284
+ #
285
+ # <tt>parts_order</tt> and <tt>charset</tt> are not actually valid <tt>Mail::Message</tt> header fields,
286
+ # but Action Mailer translates them appropriately and sets the correct values.
287
+ #
288
+ # As you can pass in any header, you need to either quote the header as a string, or pass it in as
289
+ # an underscored symbol, so the following will work:
290
+ #
291
+ # class NotifierMailer < ApplicationMailer
292
+ # default 'Content-Transfer-Encoding' => '7bit',
293
+ # content_description: 'This is a description'
294
+ # end
295
+ #
296
+ # Finally, Action Mailer also supports passing <tt>Proc</tt> and <tt>Lambda</tt> objects into the default hash,
297
+ # so you can define methods that evaluate as the message is being generated:
298
+ #
299
+ # class NotifierMailer < ApplicationMailer
300
+ # default 'X-Special-Header' => Proc.new { my_method }, to: -> { @inviter.email_address }
301
+ #
302
+ # private
303
+ # def my_method
304
+ # 'some complex call'
305
+ # end
306
+ # end
307
+ #
308
+ # Note that the proc/lambda is evaluated right at the start of the mail message generation, so if you
309
+ # set something in the default hash using a proc, and then set the same thing inside of your
310
+ # mailer method, it will get overwritten by the mailer method.
311
+ #
312
+ # It is also possible to set these default options that will be used in all mailers through
313
+ # the <tt>default_options=</tt> configuration in <tt>config/application.rb</tt>:
314
+ #
315
+ # config.action_mailer.default_options = { from: "no-reply@example.org" }
316
+ #
317
+ # = Callbacks
318
+ #
319
+ # You can specify callbacks using <tt>before_action</tt> and <tt>after_action</tt> for configuring your messages.
320
+ # This may be useful, for example, when you want to add default inline attachments for all
321
+ # messages sent out by a certain mailer class:
322
+ #
323
+ # class NotifierMailer < ApplicationMailer
324
+ # before_action :add_inline_attachment!
325
+ #
326
+ # def welcome
327
+ # mail
328
+ # end
329
+ #
330
+ # private
331
+ # def add_inline_attachment!
332
+ # attachments.inline["footer.jpg"] = File.read('/path/to/filename.jpg')
333
+ # end
334
+ # end
335
+ #
336
+ # Callbacks in Action Mailer are implemented using
337
+ # <tt>AbstractController::Callbacks</tt>, so you can define and configure
338
+ # callbacks in the same manner that you would use callbacks in classes that
339
+ # inherit from <tt>ActionController::Base</tt>.
340
+ #
341
+ # Note that unless you have a specific reason to do so, you should prefer
342
+ # using <tt>before_action</tt> rather than <tt>after_action</tt> in your
343
+ # Action Mailer classes so that headers are parsed properly.
344
+ #
345
+ # = Previewing emails
346
+ #
347
+ # You can preview your email templates visually by adding a mailer preview file to the
348
+ # <tt>ActionMailer::Base.preview_path</tt>. Since most emails do something interesting
349
+ # with database data, you'll need to write some scenarios to load messages with fake data:
350
+ #
351
+ # class NotifierMailerPreview < ActionMailer::Preview
352
+ # def welcome
353
+ # NotifierMailer.welcome(User.first)
354
+ # end
355
+ # end
356
+ #
357
+ # Methods must return a <tt>Mail::Message</tt> object which can be generated by calling the mailer
358
+ # method without the additional <tt>deliver_now</tt> / <tt>deliver_later</tt>. The location of the
359
+ # mailer previews directory can be configured using the <tt>preview_path</tt> option which has a default
360
+ # of <tt>test/mailers/previews</tt>:
361
+ #
362
+ # config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
363
+ #
364
+ # An overview of all previews is accessible at <tt>http://localhost:3000/rails/mailers</tt>
365
+ # on a running development server instance.
366
+ #
367
+ # Previews can also be intercepted in a similar manner as deliveries can be by registering
368
+ # a preview interceptor that has a <tt>previewing_email</tt> method:
369
+ #
370
+ # class CssInlineStyler
371
+ # def self.previewing_email(message)
372
+ # # inline CSS styles
373
+ # end
374
+ # end
375
+ #
376
+ # config.action_mailer.preview_interceptors :css_inline_styler
377
+ #
378
+ # Note that interceptors need to be registered both with <tt>register_interceptor</tt>
379
+ # and <tt>register_preview_interceptor</tt> if they should operate on both sending and
380
+ # previewing emails.
381
+ #
382
+ # = Configuration options
383
+ #
384
+ # These options are specified on the class level, like
385
+ # <tt>ActionMailer::Base.raise_delivery_errors = true</tt>
386
+ #
387
+ # * <tt>default_options</tt> - You can pass this in at a class level as well as within the class itself as
388
+ # per the above section.
389
+ #
390
+ # * <tt>logger</tt> - the logger is used for generating information on the mailing run if available.
391
+ # Can be set to +nil+ for no logging. Compatible with both Ruby's own +Logger+ and Log4r loggers.
392
+ #
393
+ # * <tt>smtp_settings</tt> - Allows detailed configuration for <tt>:smtp</tt> delivery method:
394
+ # * <tt>:address</tt> - Allows you to use a remote mail server. Just change it from its default
395
+ # "localhost" setting.
396
+ # * <tt>:port</tt> - On the off chance that your mail server doesn't run on port 25, you can change it.
397
+ # * <tt>:domain</tt> - If you need to specify a HELO domain, you can do it here.
398
+ # * <tt>:user_name</tt> - If your mail server requires authentication, set the username in this setting.
399
+ # * <tt>:password</tt> - If your mail server requires authentication, set the password in this setting.
400
+ # * <tt>:authentication</tt> - If your mail server requires authentication, you need to specify the
401
+ # authentication type here.
402
+ # This is a symbol and one of <tt>:plain</tt> (will send the password Base64 encoded), <tt>:login</tt> (will
403
+ # send the password Base64 encoded) or <tt>:cram_md5</tt> (combines a Challenge/Response mechanism to exchange
404
+ # information and a cryptographic Message Digest 5 algorithm to hash important information)
405
+ # * <tt>:enable_starttls_auto</tt> - Detects if STARTTLS is enabled in your SMTP server and starts
406
+ # to use it. Defaults to <tt>true</tt>.
407
+ # * <tt>:openssl_verify_mode</tt> - When using TLS, you can set how OpenSSL checks the certificate. This is
408
+ # really useful if you need to validate a self-signed and/or a wildcard certificate. You can use the name
409
+ # of an OpenSSL verify constant (<tt>'none'</tt> or <tt>'peer'</tt>) or directly the constant
410
+ # (<tt>OpenSSL::SSL::VERIFY_NONE</tt> or <tt>OpenSSL::SSL::VERIFY_PEER</tt>).
411
+ # <tt>:ssl/:tls</tt> Enables the SMTP connection to use SMTP/TLS (SMTPS: SMTP over direct TLS connection)
412
+ #
413
+ # * <tt>sendmail_settings</tt> - Allows you to override options for the <tt>:sendmail</tt> delivery method.
414
+ # * <tt>:location</tt> - The location of the sendmail executable. Defaults to <tt>/usr/sbin/sendmail</tt>.
415
+ # * <tt>:arguments</tt> - The command line arguments. Defaults to <tt>-i</tt> with <tt>-f sender@address</tt>
416
+ # added automatically before the message is sent.
417
+ #
418
+ # * <tt>file_settings</tt> - Allows you to override options for the <tt>:file</tt> delivery method.
419
+ # * <tt>:location</tt> - The directory into which emails will be written. Defaults to the application
420
+ # <tt>tmp/mails</tt>.
421
+ #
422
+ # * <tt>raise_delivery_errors</tt> - Whether or not errors should be raised if the email fails to be delivered.
423
+ #
424
+ # * <tt>delivery_method</tt> - Defines a delivery method. Possible values are <tt>:smtp</tt> (default),
425
+ # <tt>:sendmail</tt>, <tt>:test</tt>, and <tt>:file</tt>. Or you may provide a custom delivery method
426
+ # object e.g. +MyOwnDeliveryMethodClass+. See the Mail gem documentation on the interface you need to
427
+ # implement for a custom delivery agent.
428
+ #
429
+ # * <tt>perform_deliveries</tt> - Determines whether emails are actually sent from Action Mailer when you
430
+ # call <tt>.deliver</tt> on an email message or on an Action Mailer method. This is on by default but can
431
+ # be turned off to aid in functional testing.
432
+ #
433
+ # * <tt>deliveries</tt> - Keeps an array of all the emails sent out through the Action Mailer with
434
+ # <tt>delivery_method :test</tt>. Most useful for unit and functional testing.
435
+ #
436
+ # * <tt>deliver_later_queue_name</tt> - The name of the queue used with <tt>deliver_later</tt>. Defaults to +mailers+.
437
+ class Base < AbstractController::Base
438
+ include DeliveryMethods
439
+ include Rescuable
440
+ include Parameterized
441
+ include Previews
442
+
443
+ abstract!
444
+
445
+ include AbstractController::Rendering
446
+
447
+ include AbstractController::Logger
448
+ include AbstractController::Helpers
449
+ include AbstractController::Translation
450
+ include AbstractController::AssetPaths
451
+ include AbstractController::Callbacks
452
+ include AbstractController::Caching
453
+
454
+ include ActionView::Layouts
455
+
456
+ PROTECTED_IVARS = AbstractController::Rendering::DEFAULT_PROTECTED_INSTANCE_VARIABLES + [:@_action_has_layout]
457
+
458
+ def _protected_ivars # :nodoc:
459
+ PROTECTED_IVARS
460
+ end
461
+
462
+ helper ActionMailer::MailHelper
463
+
464
+ class_attribute :delivery_job, default: ::ActionMailer::DeliveryJob
465
+ class_attribute :default_params, default: {
466
+ mime_version: "1.0",
467
+ charset: "UTF-8",
468
+ content_type: "text/plain",
469
+ parts_order: [ "text/plain", "text/enriched", "text/html" ]
470
+ }.freeze
471
+
472
+ class << self
473
+ # Register one or more Observers which will be notified when mail is delivered.
474
+ def register_observers(*observers)
475
+ observers.flatten.compact.each { |observer| register_observer(observer) }
476
+ end
477
+
478
+ # Register one or more Interceptors which will be called before mail is sent.
479
+ def register_interceptors(*interceptors)
480
+ interceptors.flatten.compact.each { |interceptor| register_interceptor(interceptor) }
481
+ end
482
+
483
+ # Register an Observer which will be notified when mail is delivered.
484
+ # Either a class, string or symbol can be passed in as the Observer.
485
+ # If a string or symbol is passed in it will be camelized and constantized.
486
+ def register_observer(observer)
487
+ Mail.register_observer(observer_class_for(observer))
488
+ end
489
+
490
+ # Register an Interceptor which will be called before mail is sent.
491
+ # Either a class, string or symbol can be passed in as the Interceptor.
492
+ # If a string or symbol is passed in it will be camelized and constantized.
493
+ def register_interceptor(interceptor)
494
+ Mail.register_interceptor(observer_class_for(interceptor))
495
+ end
496
+
497
+ def observer_class_for(value) # :nodoc:
498
+ case value
499
+ when String, Symbol
500
+ value.to_s.camelize.constantize
501
+ else
502
+ value
503
+ end
504
+ end
505
+ private :observer_class_for
506
+
507
+ # Returns the name of the current mailer. This method is also being used as a path for a view lookup.
508
+ # If this is an anonymous mailer, this method will return +anonymous+ instead.
509
+ def mailer_name
510
+ @mailer_name ||= anonymous? ? "anonymous" : name.underscore
511
+ end
512
+ # Allows to set the name of current mailer.
513
+ attr_writer :mailer_name
514
+ alias :controller_path :mailer_name
515
+
516
+ # Sets the defaults through app configuration:
517
+ #
518
+ # config.action_mailer.default(from: "no-reply@example.org")
519
+ #
520
+ # Aliased by ::default_options=
521
+ def default(value = nil)
522
+ self.default_params = default_params.merge(value).freeze if value
523
+ default_params
524
+ end
525
+ # Allows to set defaults through app configuration:
526
+ #
527
+ # config.action_mailer.default_options = { from: "no-reply@example.org" }
528
+ alias :default_options= :default
529
+
530
+ # Receives a raw email, parses it into an email object, decodes it,
531
+ # instantiates a new mailer, and passes the email object to the mailer
532
+ # object's +receive+ method.
533
+ #
534
+ # If you want your mailer to be able to process incoming messages, you'll
535
+ # need to implement a +receive+ method that accepts the raw email string
536
+ # as a parameter:
537
+ #
538
+ # class MyMailer < ActionMailer::Base
539
+ # def receive(mail)
540
+ # # ...
541
+ # end
542
+ # end
543
+ def receive(raw_mail)
544
+ ActiveSupport::Notifications.instrument("receive.action_mailer") do |payload|
545
+ mail = Mail.new(raw_mail)
546
+ set_payload_for_mail(payload, mail)
547
+ new.receive(mail)
548
+ end
549
+ end
550
+
551
+ # Wraps an email delivery inside of <tt>ActiveSupport::Notifications</tt> instrumentation.
552
+ #
553
+ # This method is actually called by the <tt>Mail::Message</tt> object itself
554
+ # through a callback when you call <tt>:deliver</tt> on the <tt>Mail::Message</tt>,
555
+ # calling +deliver_mail+ directly and passing a <tt>Mail::Message</tt> will do
556
+ # nothing except tell the logger you sent the email.
557
+ def deliver_mail(mail) #:nodoc:
558
+ ActiveSupport::Notifications.instrument("deliver.action_mailer") do |payload|
559
+ set_payload_for_mail(payload, mail)
560
+ yield # Let Mail do the delivery actions
561
+ end
562
+ end
563
+
564
+ private
565
+
566
+ def set_payload_for_mail(payload, mail)
567
+ payload[:mailer] = name
568
+ payload[:message_id] = mail.message_id
569
+ payload[:subject] = mail.subject
570
+ payload[:to] = mail.to
571
+ payload[:from] = mail.from
572
+ payload[:bcc] = mail.bcc if mail.bcc.present?
573
+ payload[:cc] = mail.cc if mail.cc.present?
574
+ payload[:date] = mail.date
575
+ payload[:mail] = mail.encoded
576
+ end
577
+
578
+ def method_missing(method_name, *args)
579
+ if action_methods.include?(method_name.to_s)
580
+ MessageDelivery.new(self, method_name, *args)
581
+ else
582
+ super
583
+ end
584
+ end
585
+
586
+ def respond_to_missing?(method, include_all = false)
587
+ action_methods.include?(method.to_s) || super
588
+ end
589
+ end
590
+
591
+ attr_internal :message
592
+
593
+ def initialize
594
+ super()
595
+ @_mail_was_called = false
596
+ @_message = Mail.new
597
+ end
598
+
599
+ def process(method_name, *args) #:nodoc:
600
+ payload = {
601
+ mailer: self.class.name,
602
+ action: method_name,
603
+ args: args
604
+ }
605
+
606
+ ActiveSupport::Notifications.instrument("process.action_mailer", payload) do
607
+ super
608
+ @_message = NullMail.new unless @_mail_was_called
609
+ end
610
+ end
611
+
612
+ class NullMail #:nodoc:
613
+ def body; "" end
614
+ def header; {} end
615
+
616
+ def respond_to?(string, include_all = false)
617
+ true
618
+ end
619
+
620
+ def method_missing(*args)
621
+ nil
622
+ end
623
+ end
624
+
625
+ # Returns the name of the mailer object.
626
+ def mailer_name
627
+ self.class.mailer_name
628
+ end
629
+
630
+ # Allows you to pass random and unusual headers to the new <tt>Mail::Message</tt>
631
+ # object which will add them to itself.
632
+ #
633
+ # headers['X-Special-Domain-Specific-Header'] = "SecretValue"
634
+ #
635
+ # You can also pass a hash into headers of header field names and values,
636
+ # which will then be set on the <tt>Mail::Message</tt> object:
637
+ #
638
+ # headers 'X-Special-Domain-Specific-Header' => "SecretValue",
639
+ # 'In-Reply-To' => incoming.message_id
640
+ #
641
+ # The resulting <tt>Mail::Message</tt> will have the following in its header:
642
+ #
643
+ # X-Special-Domain-Specific-Header: SecretValue
644
+ #
645
+ # Note about replacing already defined headers:
646
+ #
647
+ # * +subject+
648
+ # * +sender+
649
+ # * +from+
650
+ # * +to+
651
+ # * +cc+
652
+ # * +bcc+
653
+ # * +reply-to+
654
+ # * +orig-date+
655
+ # * +message-id+
656
+ # * +references+
657
+ #
658
+ # Fields can only appear once in email headers while other fields such as
659
+ # <tt>X-Anything</tt> can appear multiple times.
660
+ #
661
+ # If you want to replace any header which already exists, first set it to
662
+ # +nil+ in order to reset the value otherwise another field will be added
663
+ # for the same header.
664
+ def headers(args = nil)
665
+ if args
666
+ @_message.headers(args)
667
+ else
668
+ @_message
669
+ end
670
+ end
671
+
672
+ # Allows you to add attachments to an email, like so:
673
+ #
674
+ # mail.attachments['filename.jpg'] = File.read('/path/to/filename.jpg')
675
+ #
676
+ # If you do this, then Mail will take the file name and work out the mime type.
677
+ # It will also set the Content-Type, Content-Disposition, Content-Transfer-Encoding
678
+ # and encode the contents of the attachment in Base64.
679
+ #
680
+ # You can also specify overrides if you want by passing a hash instead of a string:
681
+ #
682
+ # mail.attachments['filename.jpg'] = {mime_type: 'application/gzip',
683
+ # content: File.read('/path/to/filename.jpg')}
684
+ #
685
+ # If you want to use encoding other than Base64 then you will need to pass encoding
686
+ # type along with the pre-encoded content as Mail doesn't know how to decode the
687
+ # data:
688
+ #
689
+ # file_content = SpecialEncode(File.read('/path/to/filename.jpg'))
690
+ # mail.attachments['filename.jpg'] = {mime_type: 'application/gzip',
691
+ # encoding: 'SpecialEncoding',
692
+ # content: file_content }
693
+ #
694
+ # You can also search for specific attachments:
695
+ #
696
+ # # By Filename
697
+ # mail.attachments['filename.jpg'] # => Mail::Part object or nil
698
+ #
699
+ # # or by index
700
+ # mail.attachments[0] # => Mail::Part (first attachment)
701
+ #
702
+ def attachments
703
+ if @_mail_was_called
704
+ LateAttachmentsProxy.new(@_message.attachments)
705
+ else
706
+ @_message.attachments
707
+ end
708
+ end
709
+
710
+ class LateAttachmentsProxy < SimpleDelegator
711
+ def inline; _raise_error end
712
+ def []=(_name, _content); _raise_error end
713
+
714
+ private
715
+ def _raise_error
716
+ raise RuntimeError, "Can't add attachments after `mail` was called.\n" \
717
+ "Make sure to use `attachments[]=` before calling `mail`."
718
+ end
719
+ end
720
+
721
+ # The main method that creates the message and renders the email templates. There are
722
+ # two ways to call this method, with a block, or without a block.
723
+ #
724
+ # It accepts a headers hash. This hash allows you to specify
725
+ # the most used headers in an email message, these are:
726
+ #
727
+ # * +:subject+ - The subject of the message, if this is omitted, Action Mailer will
728
+ # ask the Rails I18n class for a translated +:subject+ in the scope of
729
+ # <tt>[mailer_scope, action_name]</tt> or if this is missing, will translate the
730
+ # humanized version of the +action_name+
731
+ # * +:to+ - Who the message is destined for, can be a string of addresses, or an array
732
+ # of addresses.
733
+ # * +:from+ - Who the message is from
734
+ # * +:cc+ - Who you would like to Carbon-Copy on this email, can be a string of addresses,
735
+ # or an array of addresses.
736
+ # * +:bcc+ - Who you would like to Blind-Carbon-Copy on this email, can be a string of
737
+ # addresses, or an array of addresses.
738
+ # * +:reply_to+ - Who to set the Reply-To header of the email to.
739
+ # * +:date+ - The date to say the email was sent on.
740
+ #
741
+ # You can set default values for any of the above headers (except +:date+)
742
+ # by using the ::default class method:
743
+ #
744
+ # class Notifier < ActionMailer::Base
745
+ # default from: 'no-reply@test.lindsaar.net',
746
+ # bcc: 'email_logger@test.lindsaar.net',
747
+ # reply_to: 'bounces@test.lindsaar.net'
748
+ # end
749
+ #
750
+ # If you need other headers not listed above, you can either pass them in
751
+ # as part of the headers hash or use the <tt>headers['name'] = value</tt>
752
+ # method.
753
+ #
754
+ # When a +:return_path+ is specified as header, that value will be used as
755
+ # the 'envelope from' address for the Mail message. Setting this is useful
756
+ # when you want delivery notifications sent to a different address than the
757
+ # one in +:from+. Mail will actually use the +:return_path+ in preference
758
+ # to the +:sender+ in preference to the +:from+ field for the 'envelope
759
+ # from' value.
760
+ #
761
+ # If you do not pass a block to the +mail+ method, it will find all
762
+ # templates in the view paths using by default the mailer name and the
763
+ # method name that it is being called from, it will then create parts for
764
+ # each of these templates intelligently, making educated guesses on correct
765
+ # content type and sequence, and return a fully prepared <tt>Mail::Message</tt>
766
+ # ready to call <tt>:deliver</tt> on to send.
767
+ #
768
+ # For example:
769
+ #
770
+ # class Notifier < ActionMailer::Base
771
+ # default from: 'no-reply@test.lindsaar.net'
772
+ #
773
+ # def welcome
774
+ # mail(to: 'mikel@test.lindsaar.net')
775
+ # end
776
+ # end
777
+ #
778
+ # Will look for all templates at "app/views/notifier" with name "welcome".
779
+ # If no welcome template exists, it will raise an ActionView::MissingTemplate error.
780
+ #
781
+ # However, those can be customized:
782
+ #
783
+ # mail(template_path: 'notifications', template_name: 'another')
784
+ #
785
+ # And now it will look for all templates at "app/views/notifications" with name "another".
786
+ #
787
+ # If you do pass a block, you can render specific templates of your choice:
788
+ #
789
+ # mail(to: 'mikel@test.lindsaar.net') do |format|
790
+ # format.text
791
+ # format.html
792
+ # end
793
+ #
794
+ # You can even render plain text directly without using a template:
795
+ #
796
+ # mail(to: 'mikel@test.lindsaar.net') do |format|
797
+ # format.text { render plain: "Hello Mikel!" }
798
+ # format.html { render html: "<h1>Hello Mikel!</h1>".html_safe }
799
+ # end
800
+ #
801
+ # Which will render a +multipart/alternative+ email with +text/plain+ and
802
+ # +text/html+ parts.
803
+ #
804
+ # The block syntax also allows you to customize the part headers if desired:
805
+ #
806
+ # mail(to: 'mikel@test.lindsaar.net') do |format|
807
+ # format.text(content_transfer_encoding: "base64")
808
+ # format.html
809
+ # end
810
+ #
811
+ def mail(headers = {}, &block)
812
+ return message if @_mail_was_called && headers.blank? && !block
813
+
814
+ # At the beginning, do not consider class default for content_type
815
+ content_type = headers[:content_type]
816
+
817
+ headers = apply_defaults(headers)
818
+
819
+ # Apply charset at the beginning so all fields are properly quoted
820
+ message.charset = charset = headers[:charset]
821
+
822
+ # Set configure delivery behavior
823
+ wrap_delivery_behavior!(headers[:delivery_method], headers[:delivery_method_options])
824
+
825
+ assign_headers_to_message(message, headers)
826
+
827
+ # Render the templates and blocks
828
+ responses = collect_responses(headers, &block)
829
+ @_mail_was_called = true
830
+
831
+ create_parts_from_responses(message, responses)
832
+
833
+ # Setup content type, reapply charset and handle parts order
834
+ message.content_type = set_content_type(message, content_type, headers[:content_type])
835
+ message.charset = charset
836
+
837
+ if message.multipart?
838
+ message.body.set_sort_order(headers[:parts_order])
839
+ message.body.sort_parts!
840
+ end
841
+
842
+ message
843
+ end
844
+
845
+ private
846
+
847
+ # Used by #mail to set the content type of the message.
848
+ #
849
+ # It will use the given +user_content_type+, or multipart if the mail
850
+ # message has any attachments. If the attachments are inline, the content
851
+ # type will be "multipart/related", otherwise "multipart/mixed".
852
+ #
853
+ # If there is no content type passed in via headers, and there are no
854
+ # attachments, or the message is multipart, then the default content type is
855
+ # used.
856
+ def set_content_type(m, user_content_type, class_default) # :doc:
857
+ params = m.content_type_parameters || {}
858
+ case
859
+ when user_content_type.present?
860
+ user_content_type
861
+ when m.has_attachments?
862
+ if m.attachments.detect(&:inline?)
863
+ ["multipart", "related", params]
864
+ else
865
+ ["multipart", "mixed", params]
866
+ end
867
+ when m.multipart?
868
+ ["multipart", "alternative", params]
869
+ else
870
+ m.content_type || class_default
871
+ end
872
+ end
873
+
874
+ # Translates the +subject+ using Rails I18n class under <tt>[mailer_scope, action_name]</tt> scope.
875
+ # If it does not find a translation for the +subject+ under the specified scope it will default to a
876
+ # humanized version of the <tt>action_name</tt>.
877
+ # If the subject has interpolations, you can pass them through the +interpolations+ parameter.
878
+ def default_i18n_subject(interpolations = {}) # :doc:
879
+ mailer_scope = self.class.mailer_name.tr("/", ".")
880
+ I18n.t(:subject, interpolations.merge(scope: [mailer_scope, action_name], default: action_name.humanize))
881
+ end
882
+
883
+ # Emails do not support relative path links.
884
+ def self.supports_path? # :doc:
885
+ false
886
+ end
887
+
888
+ def apply_defaults(headers)
889
+ default_values = self.class.default.map do |key, value|
890
+ [
891
+ key,
892
+ compute_default(value)
893
+ ]
894
+ end.to_h
895
+
896
+ headers_with_defaults = headers.reverse_merge(default_values)
897
+ headers_with_defaults[:subject] ||= default_i18n_subject
898
+ headers_with_defaults
899
+ end
900
+
901
+ def compute_default(value)
902
+ return value unless value.is_a?(Proc)
903
+
904
+ if value.arity == 1
905
+ instance_exec(self, &value)
906
+ else
907
+ instance_exec(&value)
908
+ end
909
+ end
910
+
911
+ def assign_headers_to_message(message, headers)
912
+ assignable = headers.except(:parts_order, :content_type, :body, :template_name,
913
+ :template_path, :delivery_method, :delivery_method_options)
914
+ assignable.each { |k, v| message[k] = v }
915
+ end
916
+
917
+ def collect_responses(headers)
918
+ if block_given?
919
+ collector = ActionMailer::Collector.new(lookup_context) { render(action_name) }
920
+ yield(collector)
921
+ collector.responses
922
+ elsif headers[:body]
923
+ collect_responses_from_text(headers)
924
+ else
925
+ collect_responses_from_templates(headers)
926
+ end
927
+ end
928
+
929
+ def collect_responses_from_text(headers)
930
+ [{
931
+ body: headers.delete(:body),
932
+ content_type: headers[:content_type] || "text/plain"
933
+ }]
934
+ end
935
+
936
+ def collect_responses_from_templates(headers)
937
+ templates_path = headers[:template_path] || self.class.mailer_name
938
+ templates_name = headers[:template_name] || action_name
939
+
940
+ each_template(Array(templates_path), templates_name).map do |template|
941
+ self.formats = template.formats
942
+ {
943
+ body: render(template: template),
944
+ content_type: template.type.to_s
945
+ }
946
+ end
947
+ end
948
+
949
+ def each_template(paths, name, &block)
950
+ templates = lookup_context.find_all(name, paths)
951
+ if templates.empty?
952
+ raise ActionView::MissingTemplate.new(paths, name, paths, false, "mailer")
953
+ else
954
+ templates.uniq(&:formats).each(&block)
955
+ end
956
+ end
957
+
958
+ def create_parts_from_responses(m, responses)
959
+ if responses.size == 1 && !m.has_attachments?
960
+ responses[0].each { |k, v| m[k] = v }
961
+ elsif responses.size > 1 && m.has_attachments?
962
+ container = Mail::Part.new
963
+ container.content_type = "multipart/alternative"
964
+ responses.each { |r| insert_part(container, r, m.charset) }
965
+ m.add_part(container)
966
+ else
967
+ responses.each { |r| insert_part(m, r, m.charset) }
968
+ end
969
+ end
970
+
971
+ def insert_part(container, response, charset)
972
+ response[:charset] ||= charset
973
+ part = Mail::Part.new(response)
974
+ container.add_part(part)
975
+ end
976
+
977
+ # This and #instrument_name is for caching instrument
978
+ def instrument_payload(key)
979
+ {
980
+ mailer: mailer_name,
981
+ key: key
982
+ }
983
+ end
984
+
985
+ def instrument_name
986
+ "action_mailer".freeze
987
+ end
988
+
989
+ ActiveSupport.run_load_hooks(:action_mailer, self)
990
+ end
991
+ end