actionmailer 6.0.0

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: 55ef14268d45d7a535760751b1b1fb2753af791ae34074e3ebea138f2abd5b0f
4
+ data.tar.gz: 6f3bc72286f71badba0715b37dc1fd1fdb740a97723f2d2d46f551821d61de72
5
+ SHA512:
6
+ metadata.gz: 2613c547a7061aa3bc303faedc72020cd50166347ab01065d8ac0f4a2cfeea69a174f8570a004fb95725eac3c91c85adba6265bae4559fe33b32074d3e9f13bc
7
+ data.tar.gz: e22509967176e017ed6cef838ea3cc9844d1468a32a9b769d87305cb7bac103b5604b110638a713167cda51c06166f8b690befe73a12af5d7c1eb5a1e1618024
@@ -0,0 +1,96 @@
1
+ ## Rails 6.0.0 (August 16, 2019) ##
2
+
3
+ * No changes.
4
+
5
+
6
+ ## Rails 6.0.0.rc2 (July 22, 2019) ##
7
+
8
+ * No changes.
9
+
10
+
11
+ ## Rails 6.0.0.rc1 (April 24, 2019) ##
12
+
13
+ * No changes.
14
+
15
+
16
+ ## Rails 6.0.0.beta3 (March 11, 2019) ##
17
+
18
+ * No changes.
19
+
20
+
21
+ ## Rails 6.0.0.beta2 (February 25, 2019) ##
22
+
23
+ * No changes.
24
+
25
+
26
+ ## Rails 6.0.0.beta1 (January 18, 2019) ##
27
+
28
+ * Deprecate `ActionMailer::Base.receive` in favor of [Action Mailbox](https://github.com/rails/rails/tree/master/actionmailbox).
29
+
30
+ *George Claghorn*
31
+
32
+ * Add `MailDeliveryJob` for delivering both regular and parameterized mail. Deprecate using `DeliveryJob` and `Parameterized::DeliveryJob`.
33
+
34
+ *Gannon McGibbon*
35
+
36
+ * Fix ActionMailer assertions not working when a Mail defines
37
+ a custom delivery job class
38
+
39
+ *Edouard Chin*
40
+
41
+ * Mails with multipart `format` blocks with implicit render now also check for
42
+ a template name in options hash instead of only using the action name.
43
+
44
+ *Marcus Ilgner*
45
+
46
+ * `ActionDispatch::IntegrationTest` includes `ActionMailer::TestHelper` module by default.
47
+
48
+ *Ricardo Díaz*
49
+
50
+ * Add `perform_deliveries` to a payload of `deliver.action_mailer` notification.
51
+
52
+ *Yoshiyuki Kinjo*
53
+
54
+ * Change delivery logging message when `perform_deliveries` is false.
55
+
56
+ *Yoshiyuki Kinjo*
57
+
58
+ * Allow call `assert_enqueued_email_with` with no block.
59
+
60
+ Example:
61
+ ```
62
+ def test_email
63
+ ContactMailer.welcome.deliver_later
64
+ assert_enqueued_email_with ContactMailer, :welcome
65
+ end
66
+
67
+ def test_email_with_arguments
68
+ ContactMailer.welcome("Hello", "Goodbye").deliver_later
69
+ assert_enqueued_email_with ContactMailer, :welcome, args: ["Hello", "Goodbye"]
70
+ end
71
+ ```
72
+
73
+ *bogdanvlviv*
74
+
75
+ * Ensure mail gem is eager autoloaded when eager load is true to prevent thread deadlocks.
76
+
77
+ *Samuel Cochran*
78
+
79
+ * Perform email jobs in `assert_emails`.
80
+
81
+ *Gannon McGibbon*
82
+
83
+ * Add `Base.unregister_observer`, `Base.unregister_observers`,
84
+ `Base.unregister_interceptor`, `Base.unregister_interceptors`,
85
+ `Base.unregister_preview_interceptor` and `Base.unregister_preview_interceptors`.
86
+ This makes it possible to dynamically add and remove email observers and
87
+ interceptors at runtime in the same way they're registered.
88
+
89
+ *Claudio Ortolina*, *Kota Miyake*
90
+
91
+ * Rails 6 requires Ruby 2.5.0 or newer.
92
+
93
+ *Jeremy Daer*, *Kasper Timm Hansen*
94
+
95
+
96
+ Please check [5-2-stable](https://github.com/rails/rails/blob/5-2-stable/actionmailer/CHANGELOG.md) for previous changes.
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2004-2019 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,141 @@
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
+ You can read more about Action Mailer in the {Action Mailer Basics}[https://edgeguides.rubyonrails.org/action_mailer_basics.html] guide.
17
+
18
+ == Sending emails
19
+
20
+ The framework works by initializing any instance variables you want to be
21
+ available in the email template, followed by a call to +mail+ to deliver
22
+ the email.
23
+
24
+ This can be as simple as:
25
+
26
+ class Notifier < ActionMailer::Base
27
+ default from: 'system@loudthinking.com'
28
+
29
+ def welcome(recipient)
30
+ @recipient = recipient
31
+ mail(to: recipient,
32
+ subject: "[Signed up] Welcome #{recipient}")
33
+ end
34
+ end
35
+
36
+ The body of the email is created by using an Action View template (regular
37
+ ERB) that has the instance variables that are declared in the mailer action.
38
+
39
+ So the corresponding body template for the method above could look like this:
40
+
41
+ Hello there,
42
+
43
+ Mr. <%= @recipient %>
44
+
45
+ Thank you for signing up!
46
+
47
+ If the recipient was given as "david@loudthinking.com", the email
48
+ generated would look like this:
49
+
50
+ Date: Mon, 25 Jan 2010 22:48:09 +1100
51
+ From: system@loudthinking.com
52
+ To: david@loudthinking.com
53
+ Message-ID: <4b5d84f9dd6a5_7380800b81ac29578@void.loudthinking.com.mail>
54
+ Subject: [Signed up] Welcome david@loudthinking.com
55
+ Mime-Version: 1.0
56
+ Content-Type: text/plain;
57
+ charset="US-ASCII";
58
+ Content-Transfer-Encoding: 7bit
59
+
60
+ Hello there,
61
+
62
+ Mr. david@loudthinking.com
63
+
64
+ Thank you for signing up!
65
+
66
+ In order to send mails, you simply call the method and then call +deliver_now+ on the return value.
67
+
68
+ Calling the method returns a Mail Message object:
69
+
70
+ message = Notifier.welcome("david@loudthinking.com") # => Returns a Mail::Message object
71
+ message.deliver_now # => delivers the email
72
+
73
+ Or you can just chain the methods together like:
74
+
75
+ Notifier.welcome("david@loudthinking.com").deliver_now # Creates the email and sends it immediately
76
+
77
+ == Setting defaults
78
+
79
+ It is possible to set default values that will be used in every method in your
80
+ Action Mailer class. To implement this functionality, you just call the public
81
+ class method +default+ which you get for free from <tt>ActionMailer::Base</tt>.
82
+ This method accepts a Hash as the parameter. You can use any of the headers,
83
+ email messages have, like +:from+ as the key. You can also pass in a string as
84
+ the key, like "Content-Type", but Action Mailer does this out of the box for you,
85
+ so you won't need to worry about that. Finally, it is also possible to pass in a
86
+ Proc that will get evaluated when it is needed.
87
+
88
+ Note that every value you set with this method will get overwritten if you use the
89
+ same key in your mailer method.
90
+
91
+ Example:
92
+
93
+ class AuthenticationMailer < ActionMailer::Base
94
+ default from: "awesome@application.com", subject: Proc.new { "E-mail was generated at #{Time.now}" }
95
+ .....
96
+ end
97
+
98
+ == Configuration
99
+
100
+ The Base class has the full list of configuration options. Here's an example:
101
+
102
+ ActionMailer::Base.smtp_settings = {
103
+ address: 'smtp.yourserver.com', # default: localhost
104
+ port: '25', # default: 25
105
+ user_name: 'user',
106
+ password: 'pass',
107
+ authentication: :plain # :plain, :login or :cram_md5
108
+ }
109
+
110
+
111
+ == Download and installation
112
+
113
+ The latest version of Action Mailer can be installed with RubyGems:
114
+
115
+ $ gem install actionmailer
116
+
117
+ Source code can be downloaded as part of the Rails project on GitHub:
118
+
119
+ * https://github.com/rails/rails/tree/master/actionmailer
120
+
121
+
122
+ == License
123
+
124
+ Action Mailer is released under the MIT license:
125
+
126
+ * https://opensource.org/licenses/MIT
127
+
128
+
129
+ == Support
130
+
131
+ API documentation is at
132
+
133
+ * https://api.rubyonrails.org
134
+
135
+ Bug reports for the Ruby on Rails project can be filed here:
136
+
137
+ * https://github.com/rails/rails/issues
138
+
139
+ Feature requests should be discussed on the rails-core mailing list here:
140
+
141
+ * https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # Copyright (c) 2004-2019 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
+ autoload :MailDeliveryJob
56
+
57
+ def self.eager_load!
58
+ super
59
+
60
+ require "mail"
61
+ Mail.eager_autoload!
62
+ end
63
+ end
64
+
65
+ autoload :Mime, "action_dispatch/http/mime_type"
66
+
67
+ ActiveSupport.on_load(:action_view) do
68
+ ActionView::Base.default_formats ||= Mime::SET.symbols
69
+ ActionView::Template::Types.delegate_to Mime
70
+ end
@@ -0,0 +1,1026 @@
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
+ # Unregister one or more previously registered Observers.
479
+ def unregister_observers(*observers)
480
+ observers.flatten.compact.each { |observer| unregister_observer(observer) }
481
+ end
482
+
483
+ # Register one or more Interceptors which will be called before mail is sent.
484
+ def register_interceptors(*interceptors)
485
+ interceptors.flatten.compact.each { |interceptor| register_interceptor(interceptor) }
486
+ end
487
+
488
+ # Unregister one or more previously registered Interceptors.
489
+ def unregister_interceptors(*interceptors)
490
+ interceptors.flatten.compact.each { |interceptor| unregister_interceptor(interceptor) }
491
+ end
492
+
493
+ # Register an Observer which will be notified when mail is delivered.
494
+ # Either a class, string or symbol can be passed in as the Observer.
495
+ # If a string or symbol is passed in it will be camelized and constantized.
496
+ def register_observer(observer)
497
+ Mail.register_observer(observer_class_for(observer))
498
+ end
499
+
500
+ # Unregister a previously registered Observer.
501
+ # Either a class, string or symbol can be passed in as the Observer.
502
+ # If a string or symbol is passed in it will be camelized and constantized.
503
+ def unregister_observer(observer)
504
+ Mail.unregister_observer(observer_class_for(observer))
505
+ end
506
+
507
+ # Register an Interceptor which will be called before mail is sent.
508
+ # Either a class, string or symbol can be passed in as the Interceptor.
509
+ # If a string or symbol is passed in it will be camelized and constantized.
510
+ def register_interceptor(interceptor)
511
+ Mail.register_interceptor(observer_class_for(interceptor))
512
+ end
513
+
514
+ # Unregister a previously registered Interceptor.
515
+ # Either a class, string or symbol can be passed in as the Interceptor.
516
+ # If a string or symbol is passed in it will be camelized and constantized.
517
+ def unregister_interceptor(interceptor)
518
+ Mail.unregister_interceptor(observer_class_for(interceptor))
519
+ end
520
+
521
+ def observer_class_for(value) # :nodoc:
522
+ case value
523
+ when String, Symbol
524
+ value.to_s.camelize.constantize
525
+ else
526
+ value
527
+ end
528
+ end
529
+ private :observer_class_for
530
+
531
+ # Returns the name of the current mailer. This method is also being used as a path for a view lookup.
532
+ # If this is an anonymous mailer, this method will return +anonymous+ instead.
533
+ def mailer_name
534
+ @mailer_name ||= anonymous? ? "anonymous" : name.underscore
535
+ end
536
+ # Allows to set the name of current mailer.
537
+ attr_writer :mailer_name
538
+ alias :controller_path :mailer_name
539
+
540
+ # Sets the defaults through app configuration:
541
+ #
542
+ # config.action_mailer.default(from: "no-reply@example.org")
543
+ #
544
+ # Aliased by ::default_options=
545
+ def default(value = nil)
546
+ self.default_params = default_params.merge(value).freeze if value
547
+ default_params
548
+ end
549
+ # Allows to set defaults through app configuration:
550
+ #
551
+ # config.action_mailer.default_options = { from: "no-reply@example.org" }
552
+ alias :default_options= :default
553
+
554
+ # Receives a raw email, parses it into an email object, decodes it,
555
+ # instantiates a new mailer, and passes the email object to the mailer
556
+ # object's +receive+ method.
557
+ #
558
+ # If you want your mailer to be able to process incoming messages, you'll
559
+ # need to implement a +receive+ method that accepts the raw email string
560
+ # as a parameter:
561
+ #
562
+ # class MyMailer < ActionMailer::Base
563
+ # def receive(mail)
564
+ # # ...
565
+ # end
566
+ # end
567
+ def receive(raw_mail)
568
+ ActiveSupport::Deprecation.warn(<<~MESSAGE.squish)
569
+ ActionMailer::Base.receive is deprecated and will be removed in Rails 6.1.
570
+ Use Action Mailbox to process inbound email.
571
+ MESSAGE
572
+
573
+ ActiveSupport::Notifications.instrument("receive.action_mailer") do |payload|
574
+ mail = Mail.new(raw_mail)
575
+ set_payload_for_mail(payload, mail)
576
+ new.receive(mail)
577
+ end
578
+ end
579
+
580
+ # Wraps an email delivery inside of <tt>ActiveSupport::Notifications</tt> instrumentation.
581
+ #
582
+ # This method is actually called by the <tt>Mail::Message</tt> object itself
583
+ # through a callback when you call <tt>:deliver</tt> on the <tt>Mail::Message</tt>,
584
+ # calling +deliver_mail+ directly and passing a <tt>Mail::Message</tt> will do
585
+ # nothing except tell the logger you sent the email.
586
+ def deliver_mail(mail) #:nodoc:
587
+ ActiveSupport::Notifications.instrument("deliver.action_mailer") do |payload|
588
+ set_payload_for_mail(payload, mail)
589
+ yield # Let Mail do the delivery actions
590
+ end
591
+ end
592
+
593
+ private
594
+
595
+ def set_payload_for_mail(payload, mail)
596
+ payload[:mail] = mail.encoded
597
+ payload[:mailer] = name
598
+ payload[:message_id] = mail.message_id
599
+ payload[:subject] = mail.subject
600
+ payload[:to] = mail.to
601
+ payload[:from] = mail.from
602
+ payload[:bcc] = mail.bcc if mail.bcc.present?
603
+ payload[:cc] = mail.cc if mail.cc.present?
604
+ payload[:date] = mail.date
605
+ payload[:perform_deliveries] = mail.perform_deliveries
606
+ end
607
+
608
+ def method_missing(method_name, *args)
609
+ if action_methods.include?(method_name.to_s)
610
+ MessageDelivery.new(self, method_name, *args)
611
+ else
612
+ super
613
+ end
614
+ end
615
+
616
+ def respond_to_missing?(method, include_all = false)
617
+ action_methods.include?(method.to_s) || super
618
+ end
619
+ end
620
+
621
+ attr_internal :message
622
+
623
+ def initialize
624
+ super()
625
+ @_mail_was_called = false
626
+ @_message = Mail.new
627
+ end
628
+
629
+ def process(method_name, *args) #:nodoc:
630
+ payload = {
631
+ mailer: self.class.name,
632
+ action: method_name,
633
+ args: args
634
+ }
635
+
636
+ ActiveSupport::Notifications.instrument("process.action_mailer", payload) do
637
+ super
638
+ @_message = NullMail.new unless @_mail_was_called
639
+ end
640
+ end
641
+
642
+ class NullMail #:nodoc:
643
+ def body; "" end
644
+ def header; {} end
645
+
646
+ def respond_to?(string, include_all = false)
647
+ true
648
+ end
649
+
650
+ def method_missing(*args)
651
+ nil
652
+ end
653
+ end
654
+
655
+ # Returns the name of the mailer object.
656
+ def mailer_name
657
+ self.class.mailer_name
658
+ end
659
+
660
+ # Allows you to pass random and unusual headers to the new <tt>Mail::Message</tt>
661
+ # object which will add them to itself.
662
+ #
663
+ # headers['X-Special-Domain-Specific-Header'] = "SecretValue"
664
+ #
665
+ # You can also pass a hash into headers of header field names and values,
666
+ # which will then be set on the <tt>Mail::Message</tt> object:
667
+ #
668
+ # headers 'X-Special-Domain-Specific-Header' => "SecretValue",
669
+ # 'In-Reply-To' => incoming.message_id
670
+ #
671
+ # The resulting <tt>Mail::Message</tt> will have the following in its header:
672
+ #
673
+ # X-Special-Domain-Specific-Header: SecretValue
674
+ #
675
+ # Note about replacing already defined headers:
676
+ #
677
+ # * +subject+
678
+ # * +sender+
679
+ # * +from+
680
+ # * +to+
681
+ # * +cc+
682
+ # * +bcc+
683
+ # * +reply-to+
684
+ # * +orig-date+
685
+ # * +message-id+
686
+ # * +references+
687
+ #
688
+ # Fields can only appear once in email headers while other fields such as
689
+ # <tt>X-Anything</tt> can appear multiple times.
690
+ #
691
+ # If you want to replace any header which already exists, first set it to
692
+ # +nil+ in order to reset the value otherwise another field will be added
693
+ # for the same header.
694
+ def headers(args = nil)
695
+ if args
696
+ @_message.headers(args)
697
+ else
698
+ @_message
699
+ end
700
+ end
701
+
702
+ # Allows you to add attachments to an email, like so:
703
+ #
704
+ # mail.attachments['filename.jpg'] = File.read('/path/to/filename.jpg')
705
+ #
706
+ # If you do this, then Mail will take the file name and work out the mime type.
707
+ # It will also set the Content-Type, Content-Disposition, Content-Transfer-Encoding
708
+ # and encode the contents of the attachment in Base64.
709
+ #
710
+ # You can also specify overrides if you want by passing a hash instead of a string:
711
+ #
712
+ # mail.attachments['filename.jpg'] = {mime_type: 'application/gzip',
713
+ # content: File.read('/path/to/filename.jpg')}
714
+ #
715
+ # If you want to use encoding other than Base64 then you will need to pass encoding
716
+ # type along with the pre-encoded content as Mail doesn't know how to decode the
717
+ # data:
718
+ #
719
+ # file_content = SpecialEncode(File.read('/path/to/filename.jpg'))
720
+ # mail.attachments['filename.jpg'] = {mime_type: 'application/gzip',
721
+ # encoding: 'SpecialEncoding',
722
+ # content: file_content }
723
+ #
724
+ # You can also search for specific attachments:
725
+ #
726
+ # # By Filename
727
+ # mail.attachments['filename.jpg'] # => Mail::Part object or nil
728
+ #
729
+ # # or by index
730
+ # mail.attachments[0] # => Mail::Part (first attachment)
731
+ #
732
+ def attachments
733
+ if @_mail_was_called
734
+ LateAttachmentsProxy.new(@_message.attachments)
735
+ else
736
+ @_message.attachments
737
+ end
738
+ end
739
+
740
+ class LateAttachmentsProxy < SimpleDelegator
741
+ def inline; _raise_error end
742
+ def []=(_name, _content); _raise_error end
743
+
744
+ private
745
+ def _raise_error
746
+ raise RuntimeError, "Can't add attachments after `mail` was called.\n" \
747
+ "Make sure to use `attachments[]=` before calling `mail`."
748
+ end
749
+ end
750
+
751
+ # The main method that creates the message and renders the email templates. There are
752
+ # two ways to call this method, with a block, or without a block.
753
+ #
754
+ # It accepts a headers hash. This hash allows you to specify
755
+ # the most used headers in an email message, these are:
756
+ #
757
+ # * +:subject+ - The subject of the message, if this is omitted, Action Mailer will
758
+ # ask the Rails I18n class for a translated +:subject+ in the scope of
759
+ # <tt>[mailer_scope, action_name]</tt> or if this is missing, will translate the
760
+ # humanized version of the +action_name+
761
+ # * +:to+ - Who the message is destined for, can be a string of addresses, or an array
762
+ # of addresses.
763
+ # * +:from+ - Who the message is from
764
+ # * +:cc+ - Who you would like to Carbon-Copy on this email, can be a string of addresses,
765
+ # or an array of addresses.
766
+ # * +:bcc+ - Who you would like to Blind-Carbon-Copy on this email, can be a string of
767
+ # addresses, or an array of addresses.
768
+ # * +:reply_to+ - Who to set the Reply-To header of the email to.
769
+ # * +:date+ - The date to say the email was sent on.
770
+ #
771
+ # You can set default values for any of the above headers (except +:date+)
772
+ # by using the ::default class method:
773
+ #
774
+ # class Notifier < ActionMailer::Base
775
+ # default from: 'no-reply@test.lindsaar.net',
776
+ # bcc: 'email_logger@test.lindsaar.net',
777
+ # reply_to: 'bounces@test.lindsaar.net'
778
+ # end
779
+ #
780
+ # If you need other headers not listed above, you can either pass them in
781
+ # as part of the headers hash or use the <tt>headers['name'] = value</tt>
782
+ # method.
783
+ #
784
+ # When a +:return_path+ is specified as header, that value will be used as
785
+ # the 'envelope from' address for the Mail message. Setting this is useful
786
+ # when you want delivery notifications sent to a different address than the
787
+ # one in +:from+. Mail will actually use the +:return_path+ in preference
788
+ # to the +:sender+ in preference to the +:from+ field for the 'envelope
789
+ # from' value.
790
+ #
791
+ # If you do not pass a block to the +mail+ method, it will find all
792
+ # templates in the view paths using by default the mailer name and the
793
+ # method name that it is being called from, it will then create parts for
794
+ # each of these templates intelligently, making educated guesses on correct
795
+ # content type and sequence, and return a fully prepared <tt>Mail::Message</tt>
796
+ # ready to call <tt>:deliver</tt> on to send.
797
+ #
798
+ # For example:
799
+ #
800
+ # class Notifier < ActionMailer::Base
801
+ # default from: 'no-reply@test.lindsaar.net'
802
+ #
803
+ # def welcome
804
+ # mail(to: 'mikel@test.lindsaar.net')
805
+ # end
806
+ # end
807
+ #
808
+ # Will look for all templates at "app/views/notifier" with name "welcome".
809
+ # If no welcome template exists, it will raise an ActionView::MissingTemplate error.
810
+ #
811
+ # However, those can be customized:
812
+ #
813
+ # mail(template_path: 'notifications', template_name: 'another')
814
+ #
815
+ # And now it will look for all templates at "app/views/notifications" with name "another".
816
+ #
817
+ # If you do pass a block, you can render specific templates of your choice:
818
+ #
819
+ # mail(to: 'mikel@test.lindsaar.net') do |format|
820
+ # format.text
821
+ # format.html
822
+ # end
823
+ #
824
+ # You can even render plain text directly without using a template:
825
+ #
826
+ # mail(to: 'mikel@test.lindsaar.net') do |format|
827
+ # format.text { render plain: "Hello Mikel!" }
828
+ # format.html { render html: "<h1>Hello Mikel!</h1>".html_safe }
829
+ # end
830
+ #
831
+ # Which will render a +multipart/alternative+ email with +text/plain+ and
832
+ # +text/html+ parts.
833
+ #
834
+ # The block syntax also allows you to customize the part headers if desired:
835
+ #
836
+ # mail(to: 'mikel@test.lindsaar.net') do |format|
837
+ # format.text(content_transfer_encoding: "base64")
838
+ # format.html
839
+ # end
840
+ #
841
+ def mail(headers = {}, &block)
842
+ return message if @_mail_was_called && headers.blank? && !block
843
+
844
+ # At the beginning, do not consider class default for content_type
845
+ content_type = headers[:content_type]
846
+
847
+ headers = apply_defaults(headers)
848
+
849
+ # Apply charset at the beginning so all fields are properly quoted
850
+ message.charset = charset = headers[:charset]
851
+
852
+ # Set configure delivery behavior
853
+ wrap_delivery_behavior!(headers[:delivery_method], headers[:delivery_method_options])
854
+
855
+ assign_headers_to_message(message, headers)
856
+
857
+ # Render the templates and blocks
858
+ responses = collect_responses(headers, &block)
859
+ @_mail_was_called = true
860
+
861
+ create_parts_from_responses(message, responses)
862
+
863
+ # Setup content type, reapply charset and handle parts order
864
+ message.content_type = set_content_type(message, content_type, headers[:content_type])
865
+ message.charset = charset
866
+
867
+ if message.multipart?
868
+ message.body.set_sort_order(headers[:parts_order])
869
+ message.body.sort_parts!
870
+ end
871
+
872
+ message
873
+ end
874
+
875
+ private
876
+
877
+ # Used by #mail to set the content type of the message.
878
+ #
879
+ # It will use the given +user_content_type+, or multipart if the mail
880
+ # message has any attachments. If the attachments are inline, the content
881
+ # type will be "multipart/related", otherwise "multipart/mixed".
882
+ #
883
+ # If there is no content type passed in via headers, and there are no
884
+ # attachments, or the message is multipart, then the default content type is
885
+ # used.
886
+ def set_content_type(m, user_content_type, class_default) # :doc:
887
+ params = m.content_type_parameters || {}
888
+ case
889
+ when user_content_type.present?
890
+ user_content_type
891
+ when m.has_attachments?
892
+ if m.attachments.detect(&:inline?)
893
+ ["multipart", "related", params]
894
+ else
895
+ ["multipart", "mixed", params]
896
+ end
897
+ when m.multipart?
898
+ ["multipart", "alternative", params]
899
+ else
900
+ m.content_type || class_default
901
+ end
902
+ end
903
+
904
+ # Translates the +subject+ using Rails I18n class under <tt>[mailer_scope, action_name]</tt> scope.
905
+ # If it does not find a translation for the +subject+ under the specified scope it will default to a
906
+ # humanized version of the <tt>action_name</tt>.
907
+ # If the subject has interpolations, you can pass them through the +interpolations+ parameter.
908
+ def default_i18n_subject(interpolations = {}) # :doc:
909
+ mailer_scope = self.class.mailer_name.tr("/", ".")
910
+ I18n.t(:subject, interpolations.merge(scope: [mailer_scope, action_name], default: action_name.humanize))
911
+ end
912
+
913
+ # Emails do not support relative path links.
914
+ def self.supports_path? # :doc:
915
+ false
916
+ end
917
+
918
+ def apply_defaults(headers)
919
+ default_values = self.class.default.map do |key, value|
920
+ [
921
+ key,
922
+ compute_default(value)
923
+ ]
924
+ end.to_h
925
+
926
+ headers_with_defaults = headers.reverse_merge(default_values)
927
+ headers_with_defaults[:subject] ||= default_i18n_subject
928
+ headers_with_defaults
929
+ end
930
+
931
+ def compute_default(value)
932
+ return value unless value.is_a?(Proc)
933
+
934
+ if value.arity == 1
935
+ instance_exec(self, &value)
936
+ else
937
+ instance_exec(&value)
938
+ end
939
+ end
940
+
941
+ def assign_headers_to_message(message, headers)
942
+ assignable = headers.except(:parts_order, :content_type, :body, :template_name,
943
+ :template_path, :delivery_method, :delivery_method_options)
944
+ assignable.each { |k, v| message[k] = v }
945
+ end
946
+
947
+ def collect_responses(headers, &block)
948
+ if block_given?
949
+ collect_responses_from_block(headers, &block)
950
+ elsif headers[:body]
951
+ collect_responses_from_text(headers)
952
+ else
953
+ collect_responses_from_templates(headers)
954
+ end
955
+ end
956
+
957
+ def collect_responses_from_block(headers)
958
+ templates_name = headers[:template_name] || action_name
959
+ collector = ActionMailer::Collector.new(lookup_context) { render(templates_name) }
960
+ yield(collector)
961
+ collector.responses
962
+ end
963
+
964
+ def collect_responses_from_text(headers)
965
+ [{
966
+ body: headers.delete(:body),
967
+ content_type: headers[:content_type] || "text/plain"
968
+ }]
969
+ end
970
+
971
+ def collect_responses_from_templates(headers)
972
+ templates_path = headers[:template_path] || self.class.mailer_name
973
+ templates_name = headers[:template_name] || action_name
974
+
975
+ each_template(Array(templates_path), templates_name).map do |template|
976
+ format = template.format || self.formats.first
977
+ {
978
+ body: render(template: template, formats: [format]),
979
+ content_type: Mime[format].to_s
980
+ }
981
+ end
982
+ end
983
+
984
+ def each_template(paths, name, &block)
985
+ templates = lookup_context.find_all(name, paths)
986
+ if templates.empty?
987
+ raise ActionView::MissingTemplate.new(paths, name, paths, false, "mailer")
988
+ else
989
+ templates.uniq(&:format).each(&block)
990
+ end
991
+ end
992
+
993
+ def create_parts_from_responses(m, responses)
994
+ if responses.size == 1 && !m.has_attachments?
995
+ responses[0].each { |k, v| m[k] = v }
996
+ elsif responses.size > 1 && m.has_attachments?
997
+ container = Mail::Part.new
998
+ container.content_type = "multipart/alternative"
999
+ responses.each { |r| insert_part(container, r, m.charset) }
1000
+ m.add_part(container)
1001
+ else
1002
+ responses.each { |r| insert_part(m, r, m.charset) }
1003
+ end
1004
+ end
1005
+
1006
+ def insert_part(container, response, charset)
1007
+ response[:charset] ||= charset
1008
+ part = Mail::Part.new(response)
1009
+ container.add_part(part)
1010
+ end
1011
+
1012
+ # This and #instrument_name is for caching instrument
1013
+ def instrument_payload(key)
1014
+ {
1015
+ mailer: mailer_name,
1016
+ key: key
1017
+ }
1018
+ end
1019
+
1020
+ def instrument_name
1021
+ "action_mailer"
1022
+ end
1023
+
1024
+ ActiveSupport.run_load_hooks(:action_mailer, self)
1025
+ end
1026
+ end