actionmailer_csi 2.3.5.p6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +370 -0
- data/MIT-LICENSE +21 -0
- data/README +149 -0
- data/Rakefile +99 -0
- data/install.rb +30 -0
- data/lib/action_mailer/adv_attr_accessor.rb +30 -0
- data/lib/action_mailer/base.rb +706 -0
- data/lib/action_mailer/helpers.rb +113 -0
- data/lib/action_mailer/mail_helper.rb +17 -0
- data/lib/action_mailer/part.rb +107 -0
- data/lib/action_mailer/part_container.rb +55 -0
- data/lib/action_mailer/quoting.rb +61 -0
- data/lib/action_mailer/test_case.rb +64 -0
- data/lib/action_mailer/test_helper.rb +68 -0
- data/lib/action_mailer/utils.rb +7 -0
- data/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb +1466 -0
- data/lib/action_mailer/vendor/text_format.rb +10 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb +426 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb +46 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb +46 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb +41 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb +67 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb +63 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb +581 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb +960 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb +9 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb +1130 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb +3 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb +578 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb +495 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb +6 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb +3 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb +248 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb +132 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb +1478 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb +379 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb +118 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb +58 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb +49 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb +261 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb +280 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb +337 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb +39 -0
- data/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb +5 -0
- data/lib/action_mailer/vendor/tmail.rb +17 -0
- data/lib/action_mailer/version.rb +9 -0
- data/lib/action_mailer.rb +62 -0
- data/lib/actionmailer.rb +2 -0
- data/test/abstract_unit.rb +62 -0
- data/test/asset_host_test.rb +54 -0
- data/test/delivery_method_test.rb +51 -0
- data/test/fixtures/asset_host_mailer/email_with_asset.html.erb +1 -0
- data/test/fixtures/auto_layout_mailer/hello.html.erb +1 -0
- data/test/fixtures/auto_layout_mailer/multipart.text.html.erb +1 -0
- data/test/fixtures/auto_layout_mailer/multipart.text.plain.erb +1 -0
- data/test/fixtures/explicit_layout_mailer/logout.html.erb +1 -0
- data/test/fixtures/explicit_layout_mailer/signup.html.erb +1 -0
- data/test/fixtures/first_mailer/share.erb +1 -0
- data/test/fixtures/helper_mailer/use_example_helper.erb +1 -0
- data/test/fixtures/helper_mailer/use_helper.erb +1 -0
- data/test/fixtures/helper_mailer/use_helper_method.erb +1 -0
- data/test/fixtures/helper_mailer/use_mail_helper.erb +5 -0
- data/test/fixtures/helpers/example_helper.rb +5 -0
- data/test/fixtures/layouts/auto_layout_mailer.html.erb +1 -0
- data/test/fixtures/layouts/auto_layout_mailer.text.erb +1 -0
- data/test/fixtures/layouts/spam.html.erb +1 -0
- data/test/fixtures/path.with.dots/funky_path_mailer/multipart_with_template_path_with_dots.erb +1 -0
- data/test/fixtures/raw_email +14 -0
- data/test/fixtures/raw_email10 +20 -0
- data/test/fixtures/raw_email12 +32 -0
- data/test/fixtures/raw_email13 +29 -0
- data/test/fixtures/raw_email2 +114 -0
- data/test/fixtures/raw_email3 +70 -0
- data/test/fixtures/raw_email4 +59 -0
- data/test/fixtures/raw_email5 +19 -0
- data/test/fixtures/raw_email6 +20 -0
- data/test/fixtures/raw_email7 +66 -0
- data/test/fixtures/raw_email8 +47 -0
- data/test/fixtures/raw_email9 +28 -0
- data/test/fixtures/raw_email_quoted_with_0d0a +14 -0
- data/test/fixtures/raw_email_with_invalid_characters_in_content_type +104 -0
- data/test/fixtures/raw_email_with_nested_attachment +100 -0
- data/test/fixtures/raw_email_with_partially_quoted_subject +14 -0
- data/test/fixtures/second_mailer/share.erb +1 -0
- data/test/fixtures/templates/signed_up.erb +3 -0
- data/test/fixtures/test_mailer/_subtemplate.text.plain.erb +1 -0
- data/test/fixtures/test_mailer/body_ivar.erb +2 -0
- data/test/fixtures/test_mailer/custom_templating_extension.text.html.haml +6 -0
- data/test/fixtures/test_mailer/custom_templating_extension.text.plain.haml +6 -0
- data/test/fixtures/test_mailer/implicitly_multipart_example.ignored.erb +1 -0
- data/test/fixtures/test_mailer/implicitly_multipart_example.rhtml.bak +1 -0
- data/test/fixtures/test_mailer/implicitly_multipart_example.text.html.erb +10 -0
- data/test/fixtures/test_mailer/implicitly_multipart_example.text.html.erb~ +10 -0
- data/test/fixtures/test_mailer/implicitly_multipart_example.text.plain.erb +2 -0
- data/test/fixtures/test_mailer/implicitly_multipart_example.text.yaml.erb +1 -0
- data/test/fixtures/test_mailer/included_subtemplate.text.plain.erb +1 -0
- data/test/fixtures/test_mailer/rxml_template.builder +2 -0
- data/test/fixtures/test_mailer/rxml_template.rxml +2 -0
- data/test/fixtures/test_mailer/signed_up.html.erb +3 -0
- data/test/fixtures/test_mailer/signed_up_with_url.erb +5 -0
- data/test/mail_helper_test.rb +95 -0
- data/test/mail_layout_test.rb +123 -0
- data/test/mail_render_test.rb +116 -0
- data/test/mail_service_test.rb +1081 -0
- data/test/quoting_test.rb +99 -0
- data/test/test_helper_test.rb +129 -0
- data/test/tmail_test.rb +22 -0
- data/test/url_test.rb +76 -0
- metadata +195 -0
@@ -0,0 +1,706 @@
|
|
1
|
+
module ActionMailer #:nodoc:
|
2
|
+
# Action Mailer allows you to send email from your application using a mailer model and views.
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# = Mailer Models
|
6
|
+
#
|
7
|
+
# To use Action Mailer, you need to create a mailer model.
|
8
|
+
#
|
9
|
+
# $ script/generate mailer Notifier
|
10
|
+
#
|
11
|
+
# The generated model inherits from ActionMailer::Base. Emails are defined by creating methods within the model which are then
|
12
|
+
# used to set variables to be used in the mail template, to change options on the mail, or
|
13
|
+
# to add attachments.
|
14
|
+
#
|
15
|
+
# Examples:
|
16
|
+
#
|
17
|
+
# class Notifier < ActionMailer::Base
|
18
|
+
# def signup_notification(recipient)
|
19
|
+
# recipients recipient.email_address_with_name
|
20
|
+
# bcc ["bcc@example.com", "Order Watcher <watcher@example.com>"]
|
21
|
+
# from "system@example.com"
|
22
|
+
# subject "New account information"
|
23
|
+
# body :account => recipient
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# Mailer methods have the following configuration methods available.
|
28
|
+
#
|
29
|
+
# * <tt>recipients</tt> - Takes one or more email addresses. These addresses are where your email will be delivered to. Sets the <tt>To:</tt> header.
|
30
|
+
# * <tt>subject</tt> - The subject of your email. Sets the <tt>Subject:</tt> header.
|
31
|
+
# * <tt>from</tt> - Who the email you are sending is from. Sets the <tt>From:</tt> header.
|
32
|
+
# * <tt>cc</tt> - Takes one or more email addresses. These addresses will receive a carbon copy of your email. Sets the <tt>Cc:</tt> header.
|
33
|
+
# * <tt>bcc</tt> - Takes one or more email addresses. These addresses will receive a blind carbon copy of your email. Sets the <tt>Bcc:</tt> header.
|
34
|
+
# * <tt>reply_to</tt> - Takes one or more email addresses. These addresses will be listed as the default recipients when replying to your email. Sets the <tt>Reply-To:</tt> header.
|
35
|
+
# * <tt>sent_on</tt> - The date on which the message was sent. If not set, the header wil be set by the delivery agent.
|
36
|
+
# * <tt>content_type</tt> - Specify the content type of the message. Defaults to <tt>text/plain</tt>.
|
37
|
+
# * <tt>headers</tt> - Specify additional headers to be set for the message, e.g. <tt>headers 'X-Mail-Count' => 107370</tt>.
|
38
|
+
#
|
39
|
+
# When a <tt>headers 'return-path'</tt> is specified, that value will be used as the 'envelope from'
|
40
|
+
# address. Setting this is useful when you want delivery notifications sent to a different address than
|
41
|
+
# the one in <tt>from</tt>.
|
42
|
+
#
|
43
|
+
# The <tt>body</tt> method has special behavior. It takes a hash which generates an instance variable
|
44
|
+
# named after each key in the hash containing the value that that key points to.
|
45
|
+
#
|
46
|
+
# So, for example, <tt>body :account => recipient</tt> would result
|
47
|
+
# in an instance variable <tt>@account</tt> with the value of <tt>recipient</tt> being accessible in the
|
48
|
+
# view.
|
49
|
+
#
|
50
|
+
#
|
51
|
+
# = Mailer views
|
52
|
+
#
|
53
|
+
# Like Action Controller, each mailer class has a corresponding view directory
|
54
|
+
# in which each method of the class looks for a template with its name.
|
55
|
+
# To define a template to be used with a mailing, create an <tt>.erb</tt> file with the same name as the method
|
56
|
+
# in your mailer model. For example, in the mailer defined above, the template at
|
57
|
+
# <tt>app/views/notifier/signup_notification.erb</tt> would be used to generate the email.
|
58
|
+
#
|
59
|
+
# Variables defined in the model are accessible as instance variables in the view.
|
60
|
+
#
|
61
|
+
# Emails by default are sent in plain text, so a sample view for our model example might look like this:
|
62
|
+
#
|
63
|
+
# Hi <%= @account.name %>,
|
64
|
+
# Thanks for joining our service! Please check back often.
|
65
|
+
#
|
66
|
+
# You can even use Action Pack helpers in these views. For example:
|
67
|
+
#
|
68
|
+
# You got a new note!
|
69
|
+
# <%= truncate(note.body, 25) %>
|
70
|
+
#
|
71
|
+
#
|
72
|
+
# = Generating URLs
|
73
|
+
#
|
74
|
+
# URLs can be generated in mailer views using <tt>url_for</tt> or named routes.
|
75
|
+
# Unlike controllers from Action Pack, the mailer instance doesn't have any context about the incoming request,
|
76
|
+
# so you'll need to provide all of the details needed to generate a URL.
|
77
|
+
#
|
78
|
+
# When using <tt>url_for</tt> you'll need to provide the <tt>:host</tt>, <tt>:controller</tt>, and <tt>:action</tt>:
|
79
|
+
#
|
80
|
+
# <%= url_for(:host => "example.com", :controller => "welcome", :action => "greeting") %>
|
81
|
+
#
|
82
|
+
# When using named routes you only need to supply the <tt>:host</tt>:
|
83
|
+
#
|
84
|
+
# <%= users_url(:host => "example.com") %>
|
85
|
+
#
|
86
|
+
# You will want to avoid using the <tt>name_of_route_path</tt> form of named routes because it doesn't make sense to
|
87
|
+
# generate relative URLs in email messages.
|
88
|
+
#
|
89
|
+
# It is also possible to set a default host that will be used in all mailers by setting the <tt>:host</tt> option in
|
90
|
+
# the <tt>ActionMailer::Base.default_url_options</tt> hash as follows:
|
91
|
+
#
|
92
|
+
# ActionMailer::Base.default_url_options[:host] = "example.com"
|
93
|
+
#
|
94
|
+
# This can also be set as a configuration option in <tt>config/environment.rb</tt>:
|
95
|
+
#
|
96
|
+
# config.action_mailer.default_url_options = { :host => "example.com" }
|
97
|
+
#
|
98
|
+
# If you do decide to set a default <tt>:host</tt> for your mailers you will want to use the
|
99
|
+
# <tt>:only_path => false</tt> option when using <tt>url_for</tt>. This will ensure that absolute URLs are generated because
|
100
|
+
# the <tt>url_for</tt> view helper will, by default, generate relative URLs when a <tt>:host</tt> option isn't
|
101
|
+
# explicitly provided.
|
102
|
+
#
|
103
|
+
# = Sending mail
|
104
|
+
#
|
105
|
+
# Once a mailer action and template are defined, you can deliver your message or create it and save it
|
106
|
+
# for delivery later:
|
107
|
+
#
|
108
|
+
# Notifier.deliver_signup_notification(david) # sends the email
|
109
|
+
# mail = Notifier.create_signup_notification(david) # => a tmail object
|
110
|
+
# Notifier.deliver(mail)
|
111
|
+
#
|
112
|
+
# You never instantiate your mailer class. Rather, your delivery instance
|
113
|
+
# methods are automatically wrapped in class methods that start with the word
|
114
|
+
# <tt>deliver_</tt> followed by the name of the mailer method that you would
|
115
|
+
# like to deliver. The <tt>signup_notification</tt> method defined above is
|
116
|
+
# delivered by invoking <tt>Notifier.deliver_signup_notification</tt>.
|
117
|
+
#
|
118
|
+
#
|
119
|
+
# = HTML email
|
120
|
+
#
|
121
|
+
# To send mail as HTML, make sure your view (the <tt>.erb</tt> file) generates HTML and
|
122
|
+
# set the content type to html.
|
123
|
+
#
|
124
|
+
# class MyMailer < ActionMailer::Base
|
125
|
+
# def signup_notification(recipient)
|
126
|
+
# recipients recipient.email_address_with_name
|
127
|
+
# subject "New account information"
|
128
|
+
# from "system@example.com"
|
129
|
+
# body :account => recipient
|
130
|
+
# content_type "text/html"
|
131
|
+
# end
|
132
|
+
# end
|
133
|
+
#
|
134
|
+
#
|
135
|
+
# = Multipart email
|
136
|
+
#
|
137
|
+
# You can explicitly specify multipart messages:
|
138
|
+
#
|
139
|
+
# class ApplicationMailer < ActionMailer::Base
|
140
|
+
# def signup_notification(recipient)
|
141
|
+
# recipients recipient.email_address_with_name
|
142
|
+
# subject "New account information"
|
143
|
+
# from "system@example.com"
|
144
|
+
# content_type "multipart/alternative"
|
145
|
+
#
|
146
|
+
# part :content_type => "text/html",
|
147
|
+
# :body => render_message("signup-as-html", :account => recipient)
|
148
|
+
#
|
149
|
+
# part "text/plain" do |p|
|
150
|
+
# p.body = render_message("signup-as-plain", :account => recipient)
|
151
|
+
# p.transfer_encoding = "base64"
|
152
|
+
# end
|
153
|
+
# end
|
154
|
+
# end
|
155
|
+
#
|
156
|
+
# Multipart messages can also be used implicitly because Action Mailer will automatically
|
157
|
+
# detect and use multipart templates, where each template is named after the name of the action, followed
|
158
|
+
# by the content type. Each such detected template will be added as separate part to the message.
|
159
|
+
#
|
160
|
+
# For example, if the following templates existed:
|
161
|
+
# * signup_notification.text.plain.erb
|
162
|
+
# * signup_notification.text.html.erb
|
163
|
+
# * signup_notification.text.xml.builder
|
164
|
+
# * signup_notification.text.x-yaml.erb
|
165
|
+
#
|
166
|
+
# Each would be rendered and added as a separate part to the message,
|
167
|
+
# with the corresponding content type. The content type for the entire
|
168
|
+
# message is automatically set to <tt>multipart/alternative</tt>, which indicates
|
169
|
+
# that the email contains multiple different representations of the same email
|
170
|
+
# body. The same body hash is passed to each template.
|
171
|
+
#
|
172
|
+
# Implicit template rendering is not performed if any attachments or parts have been added to the email.
|
173
|
+
# This means that you'll have to manually add each part to the email and set the content type of the email
|
174
|
+
# to <tt>multipart/alternative</tt>.
|
175
|
+
#
|
176
|
+
# = Attachments
|
177
|
+
#
|
178
|
+
# Attachments can be added by using the +attachment+ method.
|
179
|
+
#
|
180
|
+
# Example:
|
181
|
+
#
|
182
|
+
# class ApplicationMailer < ActionMailer::Base
|
183
|
+
# # attachments
|
184
|
+
# def signup_notification(recipient)
|
185
|
+
# recipients recipient.email_address_with_name
|
186
|
+
# subject "New account information"
|
187
|
+
# from "system@example.com"
|
188
|
+
#
|
189
|
+
# attachment :content_type => "image/jpeg",
|
190
|
+
# :body => File.read("an-image.jpg")
|
191
|
+
#
|
192
|
+
# attachment "application/pdf" do |a|
|
193
|
+
# a.body = generate_your_pdf_here()
|
194
|
+
# end
|
195
|
+
# end
|
196
|
+
# end
|
197
|
+
#
|
198
|
+
#
|
199
|
+
# = Configuration options
|
200
|
+
#
|
201
|
+
# These options are specified on the class level, like <tt>ActionMailer::Base.template_root = "/my/templates"</tt>
|
202
|
+
#
|
203
|
+
# * <tt>template_root</tt> - Determines the base from which template references will be made.
|
204
|
+
#
|
205
|
+
# * <tt>logger</tt> - the logger is used for generating information on the mailing run if available.
|
206
|
+
# Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
|
207
|
+
#
|
208
|
+
# * <tt>smtp_settings</tt> - Allows detailed configuration for <tt>:smtp</tt> delivery method:
|
209
|
+
# * <tt>:address</tt> - Allows you to use a remote mail server. Just change it from its default "localhost" setting.
|
210
|
+
# * <tt>:port</tt> - On the off chance that your mail server doesn't run on port 25, you can change it.
|
211
|
+
# * <tt>:domain</tt> - If you need to specify a HELO domain, you can do it here.
|
212
|
+
# * <tt>:user_name</tt> - If your mail server requires authentication, set the username in this setting.
|
213
|
+
# * <tt>:password</tt> - If your mail server requires authentication, set the password in this setting.
|
214
|
+
# * <tt>:authentication</tt> - If your mail server requires authentication, you need to specify the authentication type here.
|
215
|
+
# This is a symbol and one of <tt>:plain</tt>, <tt>:login</tt>, <tt>:cram_md5</tt>.
|
216
|
+
# * <tt>:enable_starttls_auto</tt> - When set to true, detects if STARTTLS is enabled in your SMTP server and starts to use it.
|
217
|
+
# It works only on Ruby >= 1.8.7 and Ruby >= 1.9. Default is true.
|
218
|
+
#
|
219
|
+
# * <tt>sendmail_settings</tt> - Allows you to override options for the <tt>:sendmail</tt> delivery method.
|
220
|
+
# * <tt>:location</tt> - The location of the sendmail executable. Defaults to <tt>/usr/sbin/sendmail</tt>.
|
221
|
+
# * <tt>:arguments</tt> - The command line arguments. Defaults to <tt>-i -t</tt>.
|
222
|
+
#
|
223
|
+
# * <tt>raise_delivery_errors</tt> - Whether or not errors should be raised if the email fails to be delivered.
|
224
|
+
#
|
225
|
+
# * <tt>delivery_method</tt> - Defines a delivery method. Possible values are <tt>:smtp</tt> (default), <tt>:sendmail</tt>, and <tt>:test</tt>.
|
226
|
+
#
|
227
|
+
# * <tt>perform_deliveries</tt> - Determines whether <tt>deliver_*</tt> methods are actually carried out. By default they are,
|
228
|
+
# but this can be turned off to help functional testing.
|
229
|
+
#
|
230
|
+
# * <tt>deliveries</tt> - Keeps an array of all the emails sent out through the Action Mailer with <tt>delivery_method :test</tt>. Most useful
|
231
|
+
# for unit and functional testing.
|
232
|
+
#
|
233
|
+
# * <tt>default_charset</tt> - The default charset used for the body and to encode the subject. Defaults to UTF-8. You can also
|
234
|
+
# pick a different charset from inside a method with +charset+.
|
235
|
+
#
|
236
|
+
# * <tt>default_content_type</tt> - The default content type used for the main part of the message. Defaults to "text/plain". You
|
237
|
+
# can also pick a different content type from inside a method with +content_type+.
|
238
|
+
#
|
239
|
+
# * <tt>default_mime_version</tt> - The default mime version used for the message. Defaults to <tt>1.0</tt>. You
|
240
|
+
# can also pick a different value from inside a method with +mime_version+.
|
241
|
+
#
|
242
|
+
# * <tt>default_implicit_parts_order</tt> - When a message is built implicitly (i.e. multiple parts are assembled from templates
|
243
|
+
# which specify the content type in their filenames) this variable controls how the parts are ordered. Defaults to
|
244
|
+
# <tt>["text/html", "text/enriched", "text/plain"]</tt>. Items that appear first in the array have higher priority in the mail client
|
245
|
+
# and appear last in the mime encoded message. You can also pick a different order from inside a method with
|
246
|
+
# +implicit_parts_order+.
|
247
|
+
class Base
|
248
|
+
include AdvAttrAccessor, PartContainer, Quoting, Utils
|
249
|
+
if Object.const_defined?(:ActionController)
|
250
|
+
include ActionController::UrlWriter
|
251
|
+
include ActionController::Layout
|
252
|
+
end
|
253
|
+
|
254
|
+
private_class_method :new #:nodoc:
|
255
|
+
|
256
|
+
class_inheritable_accessor :view_paths
|
257
|
+
self.view_paths = []
|
258
|
+
|
259
|
+
cattr_accessor :logger
|
260
|
+
|
261
|
+
@@smtp_settings = {
|
262
|
+
:address => "localhost",
|
263
|
+
:port => 25,
|
264
|
+
:domain => 'localhost.localdomain',
|
265
|
+
:user_name => nil,
|
266
|
+
:password => nil,
|
267
|
+
:authentication => nil,
|
268
|
+
:enable_starttls_auto => true,
|
269
|
+
}
|
270
|
+
cattr_accessor :smtp_settings
|
271
|
+
|
272
|
+
@@sendmail_settings = {
|
273
|
+
:location => '/usr/sbin/sendmail',
|
274
|
+
:arguments => '-i -t'
|
275
|
+
}
|
276
|
+
cattr_accessor :sendmail_settings
|
277
|
+
|
278
|
+
@@raise_delivery_errors = true
|
279
|
+
cattr_accessor :raise_delivery_errors
|
280
|
+
|
281
|
+
superclass_delegating_accessor :delivery_method
|
282
|
+
self.delivery_method = :smtp
|
283
|
+
|
284
|
+
@@perform_deliveries = true
|
285
|
+
cattr_accessor :perform_deliveries
|
286
|
+
|
287
|
+
@@deliveries = []
|
288
|
+
cattr_accessor :deliveries
|
289
|
+
|
290
|
+
@@default_charset = "utf-8"
|
291
|
+
cattr_accessor :default_charset
|
292
|
+
|
293
|
+
@@default_content_type = "text/plain"
|
294
|
+
cattr_accessor :default_content_type
|
295
|
+
|
296
|
+
@@default_mime_version = "1.0"
|
297
|
+
cattr_accessor :default_mime_version
|
298
|
+
|
299
|
+
@@default_implicit_parts_order = [ "text/html", "text/enriched", "text/plain" ]
|
300
|
+
cattr_accessor :default_implicit_parts_order
|
301
|
+
|
302
|
+
cattr_reader :protected_instance_variables
|
303
|
+
@@protected_instance_variables = %w(@body)
|
304
|
+
|
305
|
+
# Specify the BCC addresses for the message
|
306
|
+
adv_attr_accessor :bcc
|
307
|
+
|
308
|
+
# Define the body of the message. This is either a Hash (in which case it
|
309
|
+
# specifies the variables to pass to the template when it is rendered),
|
310
|
+
# or a string, in which case it specifies the actual text of the message.
|
311
|
+
adv_attr_accessor :body
|
312
|
+
|
313
|
+
# Specify the CC addresses for the message.
|
314
|
+
adv_attr_accessor :cc
|
315
|
+
|
316
|
+
# Specify the charset to use for the message. This defaults to the
|
317
|
+
# +default_charset+ specified for ActionMailer::Base.
|
318
|
+
adv_attr_accessor :charset
|
319
|
+
|
320
|
+
# Specify the content type for the message. This defaults to <tt>text/plain</tt>
|
321
|
+
# in most cases, but can be automatically set in some situations.
|
322
|
+
adv_attr_accessor :content_type
|
323
|
+
|
324
|
+
# Specify the from address for the message.
|
325
|
+
adv_attr_accessor :from
|
326
|
+
|
327
|
+
# Specify the address (if different than the "from" address) to direct
|
328
|
+
# replies to this message.
|
329
|
+
adv_attr_accessor :reply_to
|
330
|
+
|
331
|
+
# Specify additional headers to be added to the message.
|
332
|
+
adv_attr_accessor :headers
|
333
|
+
|
334
|
+
# Specify the order in which parts should be sorted, based on content-type.
|
335
|
+
# This defaults to the value for the +default_implicit_parts_order+.
|
336
|
+
adv_attr_accessor :implicit_parts_order
|
337
|
+
|
338
|
+
# Defaults to "1.0", but may be explicitly given if needed.
|
339
|
+
adv_attr_accessor :mime_version
|
340
|
+
|
341
|
+
# The recipient addresses for the message, either as a string (for a single
|
342
|
+
# address) or an array (for multiple addresses).
|
343
|
+
adv_attr_accessor :recipients
|
344
|
+
|
345
|
+
# The date on which the message was sent. If not set (the default), the
|
346
|
+
# header will be set by the delivery agent.
|
347
|
+
adv_attr_accessor :sent_on
|
348
|
+
|
349
|
+
# Specify the subject of the message.
|
350
|
+
adv_attr_accessor :subject
|
351
|
+
|
352
|
+
# Specify the template name to use for current message. This is the "base"
|
353
|
+
# template name, without the extension or directory, and may be used to
|
354
|
+
# have multiple mailer methods share the same template.
|
355
|
+
adv_attr_accessor :template
|
356
|
+
|
357
|
+
# Override the mailer name, which defaults to an inflected version of the
|
358
|
+
# mailer's class name. If you want to use a template in a non-standard
|
359
|
+
# location, you can use this to specify that location.
|
360
|
+
def mailer_name(value = nil)
|
361
|
+
if value
|
362
|
+
self.mailer_name = value
|
363
|
+
else
|
364
|
+
self.class.mailer_name
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
def mailer_name=(value)
|
369
|
+
self.class.mailer_name = value
|
370
|
+
end
|
371
|
+
|
372
|
+
# The mail object instance referenced by this mailer.
|
373
|
+
attr_reader :mail
|
374
|
+
attr_reader :template_name, :default_template_name, :action_name
|
375
|
+
|
376
|
+
class << self
|
377
|
+
attr_writer :mailer_name
|
378
|
+
|
379
|
+
def mailer_name
|
380
|
+
@mailer_name ||= name.underscore
|
381
|
+
end
|
382
|
+
|
383
|
+
# for ActionView compatibility
|
384
|
+
alias_method :controller_name, :mailer_name
|
385
|
+
alias_method :controller_path, :mailer_name
|
386
|
+
|
387
|
+
def respond_to?(method_symbol, include_private = false) #:nodoc:
|
388
|
+
matches_dynamic_method?(method_symbol) || super
|
389
|
+
end
|
390
|
+
|
391
|
+
def method_missing(method_symbol, *parameters) #:nodoc:
|
392
|
+
if match = matches_dynamic_method?(method_symbol)
|
393
|
+
case match[1]
|
394
|
+
when 'create' then new(match[2], *parameters).mail
|
395
|
+
when 'deliver' then new(match[2], *parameters).deliver!
|
396
|
+
when 'new' then nil
|
397
|
+
else super
|
398
|
+
end
|
399
|
+
else
|
400
|
+
super
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
# Receives a raw email, parses it into an email object, decodes it,
|
405
|
+
# instantiates a new mailer, and passes the email object to the mailer
|
406
|
+
# object's +receive+ method. If you want your mailer to be able to
|
407
|
+
# process incoming messages, you'll need to implement a +receive+
|
408
|
+
# method that accepts the email object as a parameter:
|
409
|
+
#
|
410
|
+
# class MyMailer < ActionMailer::Base
|
411
|
+
# def receive(mail)
|
412
|
+
# ...
|
413
|
+
# end
|
414
|
+
# end
|
415
|
+
def receive(raw_email)
|
416
|
+
logger.info "Received mail:\n #{raw_email}" unless logger.nil?
|
417
|
+
mail = TMail::Mail.parse(raw_email)
|
418
|
+
mail.base64_decode
|
419
|
+
new.receive(mail)
|
420
|
+
end
|
421
|
+
|
422
|
+
# Deliver the given mail object directly. This can be used to deliver
|
423
|
+
# a preconstructed mail object, like:
|
424
|
+
#
|
425
|
+
# email = MyMailer.create_some_mail(parameters)
|
426
|
+
# email.set_some_obscure_header "frobnicate"
|
427
|
+
# MyMailer.deliver(email)
|
428
|
+
def deliver(mail)
|
429
|
+
new.deliver!(mail)
|
430
|
+
end
|
431
|
+
|
432
|
+
def template_root
|
433
|
+
self.view_paths && self.view_paths.first
|
434
|
+
end
|
435
|
+
|
436
|
+
def template_root=(root)
|
437
|
+
self.view_paths = ActionView::Base.process_view_paths(root)
|
438
|
+
end
|
439
|
+
|
440
|
+
private
|
441
|
+
def matches_dynamic_method?(method_name) #:nodoc:
|
442
|
+
method_name = method_name.to_s
|
443
|
+
/^(create|deliver)_([_a-z]\w*)/.match(method_name) || /^(new)$/.match(method_name)
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
# Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer
|
448
|
+
# will be initialized according to the named method. If not, the mailer will
|
449
|
+
# remain uninitialized (useful when you only need to invoke the "receive"
|
450
|
+
# method, for instance).
|
451
|
+
def initialize(method_name=nil, *parameters) #:nodoc:
|
452
|
+
create!(method_name, *parameters) if method_name
|
453
|
+
end
|
454
|
+
|
455
|
+
# Initialize the mailer via the given +method_name+. The body will be
|
456
|
+
# rendered and a new TMail::Mail object created.
|
457
|
+
def create!(method_name, *parameters) #:nodoc:
|
458
|
+
initialize_defaults(method_name)
|
459
|
+
__send__(method_name, *parameters)
|
460
|
+
|
461
|
+
# If an explicit, textual body has not been set, we check assumptions.
|
462
|
+
unless String === @body
|
463
|
+
# First, we look to see if there are any likely templates that match,
|
464
|
+
# which include the content-type in their file name (i.e.,
|
465
|
+
# "the_template_file.text.html.erb", etc.). Only do this if parts
|
466
|
+
# have not already been specified manually.
|
467
|
+
if @parts.empty?
|
468
|
+
Dir.glob("#{template_path}/#{@template}.*").each do |path|
|
469
|
+
template = template_root["#{mailer_name}/#{File.basename(path)}"]
|
470
|
+
|
471
|
+
# Skip unless template has a multipart format
|
472
|
+
next unless template && template.multipart?
|
473
|
+
|
474
|
+
@parts << Part.new(
|
475
|
+
:content_type => template.content_type,
|
476
|
+
:disposition => "inline",
|
477
|
+
:charset => charset,
|
478
|
+
:body => render_message(template, @body)
|
479
|
+
)
|
480
|
+
end
|
481
|
+
unless @parts.empty?
|
482
|
+
@content_type = "multipart/alternative" if @content_type !~ /^multipart/
|
483
|
+
@parts = sort_parts(@parts, @implicit_parts_order)
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
# Then, if there were such templates, we check to see if we ought to
|
488
|
+
# also render a "normal" template (without the content type). If a
|
489
|
+
# normal template exists (or if there were no implicit parts) we render
|
490
|
+
# it.
|
491
|
+
template_exists = @parts.empty?
|
492
|
+
template_exists ||= template_root["#{mailer_name}/#{@template}"]
|
493
|
+
@body = render_message(@template, @body) if template_exists
|
494
|
+
|
495
|
+
# Finally, if there are other message parts and a textual body exists,
|
496
|
+
# we shift it onto the front of the parts and set the body to nil (so
|
497
|
+
# that create_mail doesn't try to render it in addition to the parts).
|
498
|
+
if !@parts.empty? && String === @body
|
499
|
+
@parts.unshift Part.new(:charset => charset, :body => @body)
|
500
|
+
@body = nil
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
# If this is a multipart e-mail add the mime_version if it is not
|
505
|
+
# already set.
|
506
|
+
@mime_version ||= "1.0" if !@parts.empty?
|
507
|
+
|
508
|
+
# build the mail object itself
|
509
|
+
@mail = create_mail
|
510
|
+
end
|
511
|
+
|
512
|
+
# Delivers a TMail::Mail object. By default, it delivers the cached mail
|
513
|
+
# object (from the <tt>create!</tt> method). If no cached mail object exists, and
|
514
|
+
# no alternate has been given as the parameter, this will fail.
|
515
|
+
def deliver!(mail = @mail)
|
516
|
+
raise "no mail object available for delivery!" unless mail
|
517
|
+
unless logger.nil?
|
518
|
+
logger.info "Sent mail to #{Array(recipients).join(', ')}"
|
519
|
+
logger.debug "\n#{mail.encoded}"
|
520
|
+
end
|
521
|
+
|
522
|
+
begin
|
523
|
+
__send__("perform_delivery_#{delivery_method}", mail) if perform_deliveries
|
524
|
+
rescue Exception => e # Net::SMTP errors or sendmail pipe errors
|
525
|
+
raise e if raise_delivery_errors
|
526
|
+
end
|
527
|
+
|
528
|
+
return mail
|
529
|
+
end
|
530
|
+
|
531
|
+
private
|
532
|
+
# Set up the default values for the various instance variables of this
|
533
|
+
# mailer. Subclasses may override this method to provide different
|
534
|
+
# defaults.
|
535
|
+
def initialize_defaults(method_name)
|
536
|
+
@charset ||= @@default_charset.dup
|
537
|
+
@content_type ||= @@default_content_type.dup
|
538
|
+
@implicit_parts_order ||= @@default_implicit_parts_order.dup
|
539
|
+
@template ||= method_name
|
540
|
+
@default_template_name = @action_name = @template
|
541
|
+
@mailer_name ||= self.class.name.underscore
|
542
|
+
@parts ||= []
|
543
|
+
@headers ||= {}
|
544
|
+
@body ||= {}
|
545
|
+
@mime_version = @@default_mime_version.dup if @@default_mime_version
|
546
|
+
@sent_on ||= Time.now
|
547
|
+
end
|
548
|
+
|
549
|
+
def render_message(method_name, body)
|
550
|
+
if method_name.respond_to?(:content_type)
|
551
|
+
@current_template_content_type = method_name.content_type
|
552
|
+
end
|
553
|
+
render :file => method_name, :body => body
|
554
|
+
ensure
|
555
|
+
@current_template_content_type = nil
|
556
|
+
end
|
557
|
+
|
558
|
+
def render(opts)
|
559
|
+
body = opts.delete(:body)
|
560
|
+
if opts[:file] && (opts[:file] !~ /\// && !opts[:file].respond_to?(:render))
|
561
|
+
opts[:file] = "#{mailer_name}/#{opts[:file]}"
|
562
|
+
end
|
563
|
+
|
564
|
+
begin
|
565
|
+
old_template, @template = @template, initialize_template_class(body)
|
566
|
+
layout = respond_to?(:pick_layout, true) ? pick_layout(opts) : false
|
567
|
+
@template.render(opts.merge(:layout => layout))
|
568
|
+
ensure
|
569
|
+
@template = old_template
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
def default_template_format
|
574
|
+
if @current_template_content_type
|
575
|
+
Mime::Type.lookup(@current_template_content_type).to_sym
|
576
|
+
else
|
577
|
+
:html
|
578
|
+
end
|
579
|
+
end
|
580
|
+
|
581
|
+
def candidate_for_layout?(options)
|
582
|
+
!self.view_paths.find_template(default_template_name, default_template_format).exempt_from_layout?
|
583
|
+
rescue ActionView::MissingTemplate
|
584
|
+
return true
|
585
|
+
end
|
586
|
+
|
587
|
+
def template_root
|
588
|
+
self.class.template_root
|
589
|
+
end
|
590
|
+
|
591
|
+
def template_root=(root)
|
592
|
+
self.class.template_root = root
|
593
|
+
end
|
594
|
+
|
595
|
+
def template_path
|
596
|
+
"#{template_root}/#{mailer_name}"
|
597
|
+
end
|
598
|
+
|
599
|
+
def initialize_template_class(assigns)
|
600
|
+
template = ActionView::Base.new(self.class.view_paths, assigns, self)
|
601
|
+
template.template_format = default_template_format
|
602
|
+
template
|
603
|
+
end
|
604
|
+
|
605
|
+
def sort_parts(parts, order = [])
|
606
|
+
order = order.collect { |s| s.downcase }
|
607
|
+
|
608
|
+
parts = parts.sort do |a, b|
|
609
|
+
a_ct = a.content_type.downcase
|
610
|
+
b_ct = b.content_type.downcase
|
611
|
+
|
612
|
+
a_in = order.include? a_ct
|
613
|
+
b_in = order.include? b_ct
|
614
|
+
|
615
|
+
s = case
|
616
|
+
when a_in && b_in
|
617
|
+
order.index(a_ct) <=> order.index(b_ct)
|
618
|
+
when a_in
|
619
|
+
-1
|
620
|
+
when b_in
|
621
|
+
1
|
622
|
+
else
|
623
|
+
a_ct <=> b_ct
|
624
|
+
end
|
625
|
+
|
626
|
+
# reverse the ordering because parts that come last are displayed
|
627
|
+
# first in mail clients
|
628
|
+
(s * -1)
|
629
|
+
end
|
630
|
+
|
631
|
+
parts
|
632
|
+
end
|
633
|
+
|
634
|
+
def create_mail
|
635
|
+
m = TMail::Mail.new
|
636
|
+
|
637
|
+
m.subject, = quote_any_if_necessary(charset, subject)
|
638
|
+
m.to, m.from = quote_any_address_if_necessary(charset, recipients, from)
|
639
|
+
m.bcc = quote_address_if_necessary(bcc, charset) unless bcc.nil?
|
640
|
+
m.cc = quote_address_if_necessary(cc, charset) unless cc.nil?
|
641
|
+
m.reply_to = quote_address_if_necessary(reply_to, charset) unless reply_to.nil?
|
642
|
+
m.mime_version = mime_version unless mime_version.nil?
|
643
|
+
m.date = sent_on.to_time rescue sent_on if sent_on
|
644
|
+
|
645
|
+
headers.each { |k, v| m[k] = v }
|
646
|
+
|
647
|
+
real_content_type, ctype_attrs = parse_content_type
|
648
|
+
|
649
|
+
if @parts.empty?
|
650
|
+
m.set_content_type(real_content_type, nil, ctype_attrs)
|
651
|
+
m.body = normalize_new_lines(body)
|
652
|
+
else
|
653
|
+
if String === body
|
654
|
+
part = TMail::Mail.new
|
655
|
+
part.body = normalize_new_lines(body)
|
656
|
+
part.set_content_type(real_content_type, nil, ctype_attrs)
|
657
|
+
part.set_content_disposition "inline"
|
658
|
+
m.parts << part
|
659
|
+
end
|
660
|
+
|
661
|
+
@parts.each do |p|
|
662
|
+
part = (TMail::Mail === p ? p : p.to_mail(self))
|
663
|
+
m.parts << part
|
664
|
+
end
|
665
|
+
|
666
|
+
if real_content_type =~ /multipart/
|
667
|
+
ctype_attrs.delete "charset"
|
668
|
+
m.set_content_type(real_content_type, nil, ctype_attrs)
|
669
|
+
end
|
670
|
+
end
|
671
|
+
|
672
|
+
@mail = m
|
673
|
+
end
|
674
|
+
|
675
|
+
def perform_delivery_smtp(mail)
|
676
|
+
destinations = mail.destinations
|
677
|
+
mail.ready_to_send
|
678
|
+
sender = (mail['return-path'] && mail['return-path'].spec) || mail['from']
|
679
|
+
|
680
|
+
smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port])
|
681
|
+
smtp.enable_starttls_auto if smtp_settings[:enable_starttls_auto] && smtp.respond_to?(:enable_starttls_auto)
|
682
|
+
smtp.start(smtp_settings[:domain], smtp_settings[:user_name], smtp_settings[:password],
|
683
|
+
smtp_settings[:authentication]) do |smtp|
|
684
|
+
smtp.sendmail(mail.encoded, sender, destinations)
|
685
|
+
end
|
686
|
+
end
|
687
|
+
|
688
|
+
def perform_delivery_sendmail(mail)
|
689
|
+
sendmail_args = sendmail_settings[:arguments]
|
690
|
+
sendmail_args += " -f \"#{mail['return-path']}\"" if mail['return-path']
|
691
|
+
IO.popen("#{sendmail_settings[:location]} #{sendmail_args}","w+") do |sm|
|
692
|
+
sm.print(mail.encoded.gsub(/\r/, ''))
|
693
|
+
sm.flush
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
def perform_delivery_test(mail)
|
698
|
+
deliveries << mail
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
702
|
+
Base.class_eval do
|
703
|
+
include Helpers
|
704
|
+
helper MailHelper
|
705
|
+
end
|
706
|
+
end
|