actionmailer_csi 2.3.5.p6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. data/CHANGELOG +370 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +149 -0
  4. data/Rakefile +99 -0
  5. data/install.rb +30 -0
  6. data/lib/action_mailer/adv_attr_accessor.rb +30 -0
  7. data/lib/action_mailer/base.rb +706 -0
  8. data/lib/action_mailer/helpers.rb +113 -0
  9. data/lib/action_mailer/mail_helper.rb +17 -0
  10. data/lib/action_mailer/part.rb +107 -0
  11. data/lib/action_mailer/part_container.rb +55 -0
  12. data/lib/action_mailer/quoting.rb +61 -0
  13. data/lib/action_mailer/test_case.rb +64 -0
  14. data/lib/action_mailer/test_helper.rb +68 -0
  15. data/lib/action_mailer/utils.rb +7 -0
  16. data/lib/action_mailer/vendor/text-format-0.6.3/text/format.rb +1466 -0
  17. data/lib/action_mailer/vendor/text_format.rb +10 -0
  18. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb +426 -0
  19. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb +46 -0
  20. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb +46 -0
  21. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb +41 -0
  22. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb +67 -0
  23. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb +63 -0
  24. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb +581 -0
  25. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb +960 -0
  26. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb +9 -0
  27. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb +1130 -0
  28. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb +3 -0
  29. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb +578 -0
  30. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb +495 -0
  31. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb +6 -0
  32. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb +3 -0
  33. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb +248 -0
  34. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb +132 -0
  35. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb +1478 -0
  36. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb +379 -0
  37. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb +118 -0
  38. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb +58 -0
  39. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb +49 -0
  40. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb +261 -0
  41. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb +280 -0
  42. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb +337 -0
  43. data/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb +39 -0
  44. data/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb +5 -0
  45. data/lib/action_mailer/vendor/tmail.rb +17 -0
  46. data/lib/action_mailer/version.rb +9 -0
  47. data/lib/action_mailer.rb +62 -0
  48. data/lib/actionmailer.rb +2 -0
  49. data/test/abstract_unit.rb +62 -0
  50. data/test/asset_host_test.rb +54 -0
  51. data/test/delivery_method_test.rb +51 -0
  52. data/test/fixtures/asset_host_mailer/email_with_asset.html.erb +1 -0
  53. data/test/fixtures/auto_layout_mailer/hello.html.erb +1 -0
  54. data/test/fixtures/auto_layout_mailer/multipart.text.html.erb +1 -0
  55. data/test/fixtures/auto_layout_mailer/multipart.text.plain.erb +1 -0
  56. data/test/fixtures/explicit_layout_mailer/logout.html.erb +1 -0
  57. data/test/fixtures/explicit_layout_mailer/signup.html.erb +1 -0
  58. data/test/fixtures/first_mailer/share.erb +1 -0
  59. data/test/fixtures/helper_mailer/use_example_helper.erb +1 -0
  60. data/test/fixtures/helper_mailer/use_helper.erb +1 -0
  61. data/test/fixtures/helper_mailer/use_helper_method.erb +1 -0
  62. data/test/fixtures/helper_mailer/use_mail_helper.erb +5 -0
  63. data/test/fixtures/helpers/example_helper.rb +5 -0
  64. data/test/fixtures/layouts/auto_layout_mailer.html.erb +1 -0
  65. data/test/fixtures/layouts/auto_layout_mailer.text.erb +1 -0
  66. data/test/fixtures/layouts/spam.html.erb +1 -0
  67. data/test/fixtures/path.with.dots/funky_path_mailer/multipart_with_template_path_with_dots.erb +1 -0
  68. data/test/fixtures/raw_email +14 -0
  69. data/test/fixtures/raw_email10 +20 -0
  70. data/test/fixtures/raw_email12 +32 -0
  71. data/test/fixtures/raw_email13 +29 -0
  72. data/test/fixtures/raw_email2 +114 -0
  73. data/test/fixtures/raw_email3 +70 -0
  74. data/test/fixtures/raw_email4 +59 -0
  75. data/test/fixtures/raw_email5 +19 -0
  76. data/test/fixtures/raw_email6 +20 -0
  77. data/test/fixtures/raw_email7 +66 -0
  78. data/test/fixtures/raw_email8 +47 -0
  79. data/test/fixtures/raw_email9 +28 -0
  80. data/test/fixtures/raw_email_quoted_with_0d0a +14 -0
  81. data/test/fixtures/raw_email_with_invalid_characters_in_content_type +104 -0
  82. data/test/fixtures/raw_email_with_nested_attachment +100 -0
  83. data/test/fixtures/raw_email_with_partially_quoted_subject +14 -0
  84. data/test/fixtures/second_mailer/share.erb +1 -0
  85. data/test/fixtures/templates/signed_up.erb +3 -0
  86. data/test/fixtures/test_mailer/_subtemplate.text.plain.erb +1 -0
  87. data/test/fixtures/test_mailer/body_ivar.erb +2 -0
  88. data/test/fixtures/test_mailer/custom_templating_extension.text.html.haml +6 -0
  89. data/test/fixtures/test_mailer/custom_templating_extension.text.plain.haml +6 -0
  90. data/test/fixtures/test_mailer/implicitly_multipart_example.ignored.erb +1 -0
  91. data/test/fixtures/test_mailer/implicitly_multipart_example.rhtml.bak +1 -0
  92. data/test/fixtures/test_mailer/implicitly_multipart_example.text.html.erb +10 -0
  93. data/test/fixtures/test_mailer/implicitly_multipart_example.text.html.erb~ +10 -0
  94. data/test/fixtures/test_mailer/implicitly_multipart_example.text.plain.erb +2 -0
  95. data/test/fixtures/test_mailer/implicitly_multipart_example.text.yaml.erb +1 -0
  96. data/test/fixtures/test_mailer/included_subtemplate.text.plain.erb +1 -0
  97. data/test/fixtures/test_mailer/rxml_template.builder +2 -0
  98. data/test/fixtures/test_mailer/rxml_template.rxml +2 -0
  99. data/test/fixtures/test_mailer/signed_up.html.erb +3 -0
  100. data/test/fixtures/test_mailer/signed_up_with_url.erb +5 -0
  101. data/test/mail_helper_test.rb +95 -0
  102. data/test/mail_layout_test.rb +123 -0
  103. data/test/mail_render_test.rb +116 -0
  104. data/test/mail_service_test.rb +1081 -0
  105. data/test/quoting_test.rb +99 -0
  106. data/test/test_helper_test.rb +129 -0
  107. data/test/tmail_test.rb +22 -0
  108. data/test/url_test.rb +76 -0
  109. 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