actionmailer 1.0.1 → 1.1.1
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.
- data/CHANGELOG +34 -0
- data/lib/action_mailer.rb +2 -4
- data/lib/action_mailer/adv_attr_accessor.rb +0 -29
- data/lib/action_mailer/base.rb +141 -44
- data/lib/action_mailer/helpers.rb +3 -3
- data/lib/action_mailer/mail_helper.rb +5 -3
- data/lib/action_mailer/part.rb +35 -3
- data/lib/action_mailer/part_container.rb +18 -1
- data/lib/action_mailer/quoting.rb +8 -48
- data/lib/action_mailer/vendor/text/format.rb +33 -14
- data/lib/action_mailer/vendor/tmail/address.rb +22 -3
- data/lib/action_mailer/vendor/tmail/attachments.rb +3 -1
- data/lib/action_mailer/vendor/tmail/base64.rb +22 -3
- data/lib/action_mailer/vendor/tmail/config.rb +22 -3
- data/lib/action_mailer/vendor/tmail/encode.rb +22 -3
- data/lib/action_mailer/vendor/tmail/facade.rb +22 -3
- data/lib/action_mailer/vendor/tmail/header.rb +27 -6
- data/lib/action_mailer/vendor/tmail/info.rb +22 -3
- data/lib/action_mailer/vendor/tmail/mail.rb +22 -3
- data/lib/action_mailer/vendor/tmail/mailbox.rb +22 -3
- data/lib/action_mailer/vendor/tmail/net.rb +22 -3
- data/lib/action_mailer/vendor/tmail/obsolete.rb +22 -3
- data/lib/action_mailer/vendor/tmail/parser.rb +22 -3
- data/lib/action_mailer/vendor/tmail/port.rb +22 -3
- data/lib/action_mailer/vendor/tmail/quoting.rb +6 -5
- data/lib/action_mailer/vendor/tmail/scanner.rb +22 -3
- data/lib/action_mailer/vendor/tmail/scanner_r.rb +22 -3
- data/lib/action_mailer/vendor/tmail/stringio.rb +22 -5
- data/lib/action_mailer/vendor/tmail/utils.rb +22 -3
- data/lib/action_mailer/version.rb +9 -0
- data/rakefile +5 -4
- data/test/fixtures/raw_email12 +32 -0
- data/test/mail_render_test.rb +48 -0
- data/test/mail_service_test.rb +62 -5
- data/test/quoting_test.rb +48 -0
- data/test/tmail_test.rb +17 -0
- metadata +8 -3
data/CHANGELOG
CHANGED
@@ -1,3 +1,37 @@
|
|
1
|
+
*1.1.1* (October 19th, 2005)
|
2
|
+
|
3
|
+
* Upgraded to Action Pack 1.10.1
|
4
|
+
|
5
|
+
|
6
|
+
*1.1.0* (October 16th, 2005)
|
7
|
+
|
8
|
+
* Update and extend documentation (rdoc)
|
9
|
+
|
10
|
+
* Minero Aoki made TMail available to Rails/ActionMailer under the MIT license (instead of LGPL) [RubyConf '05]
|
11
|
+
|
12
|
+
* Austin Ziegler made Text::Simple available to Rails/ActionMailer under a MIT-like licens [See rails ML, subject "Text::Format Licence Exception" on Oct 15, 2005]
|
13
|
+
|
14
|
+
* Fix vendor require paths to prevent files being required twice
|
15
|
+
|
16
|
+
* Don't add charset to content-type header for a part that contains subparts (for AOL compatibility) #2013 [John Long]
|
17
|
+
|
18
|
+
* Preserve underscores when unquoting message bodies #1930
|
19
|
+
|
20
|
+
* Encode multibyte characters correctly #1894
|
21
|
+
|
22
|
+
* Multipart messages specify a MIME-Version header automatically #2003 [John Long]
|
23
|
+
|
24
|
+
* Add a unified render method to ActionMailer (delegates to ActionView::Base#render)
|
25
|
+
|
26
|
+
* Move mailer initialization to a separate (overridable) method, so that subclasses may alter the various defaults #1727
|
27
|
+
|
28
|
+
* Look at content-location header (if available) to determine filename of attachments #1670
|
29
|
+
|
30
|
+
* ActionMailer::Base.deliver(email) had been accidentally removed, but was documented in the Rails book #1849
|
31
|
+
|
32
|
+
* Fix problem with sendmail delivery where headers should be delimited by \n characters instead of \r\n, which confuses some mail readers #1742 [Kent Sibilev]
|
33
|
+
|
34
|
+
|
1
35
|
*1.0.1* (11 July, 2005)
|
2
36
|
|
3
37
|
* Bind to Action Pack 1.9.1
|
data/lib/action_mailer.rb
CHANGED
@@ -38,7 +38,7 @@ require 'action_mailer/base'
|
|
38
38
|
require 'action_mailer/helpers'
|
39
39
|
require 'action_mailer/mail_helper'
|
40
40
|
require 'action_mailer/quoting'
|
41
|
-
require '
|
41
|
+
require 'tmail'
|
42
42
|
require 'net/smtp'
|
43
43
|
|
44
44
|
ActionMailer::Base.class_eval do
|
@@ -48,6 +48,4 @@ ActionMailer::Base.class_eval do
|
|
48
48
|
helper MailHelper
|
49
49
|
end
|
50
50
|
|
51
|
-
|
52
|
-
TMail::Encoder.const_set("MAX_LINE_LEN", 200)
|
53
|
-
$VERBOSE = old_verbose
|
51
|
+
silence_warnings { TMail::Encoder.const_set("MAX_LINE_LEN", 200) }
|
@@ -25,32 +25,3 @@ module ActionMailer
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
29
|
-
module ActionMailer
|
30
|
-
module AdvAttrAccessor #:nodoc:
|
31
|
-
def self.append_features(base)
|
32
|
-
super
|
33
|
-
base.extend(ClassMethods)
|
34
|
-
end
|
35
|
-
|
36
|
-
module ClassMethods #:nodoc:
|
37
|
-
def adv_attr_accessor(*names)
|
38
|
-
names.each do |name|
|
39
|
-
define_method("#{name}=") do |value|
|
40
|
-
instance_variable_set("@#{name}", value)
|
41
|
-
end
|
42
|
-
|
43
|
-
define_method(name) do |*parameters|
|
44
|
-
raise ArgumentError, "expected 0 or 1 parameters" unless parameters.length <= 1
|
45
|
-
if parameters.empty?
|
46
|
-
instance_variable_get("@#{name}")
|
47
|
-
else
|
48
|
-
instance_variable_set("@#{name}", parameters.first)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
data/lib/action_mailer/base.rb
CHANGED
@@ -4,7 +4,7 @@ require 'action_mailer/part_container'
|
|
4
4
|
require 'action_mailer/utils'
|
5
5
|
require 'tmail/net'
|
6
6
|
|
7
|
-
module ActionMailer
|
7
|
+
module ActionMailer
|
8
8
|
# Usage:
|
9
9
|
#
|
10
10
|
# class ApplicationMailer < ActionMailer::Base
|
@@ -110,6 +110,9 @@ module ActionMailer #:nodoc:
|
|
110
110
|
# pick a different charset from inside a method with <tt>@charset</tt>.
|
111
111
|
# * <tt>default_content_type</tt> - The default content type used for main part of the message. Defaults to "text/plain". You
|
112
112
|
# can also pick a different content type from inside a method with <tt>@content_type</tt>.
|
113
|
+
# * <tt>default_mime_version</tt> - The default mime version used for the message. Defaults to nil. You
|
114
|
+
# can also pick a different value from inside a method with <tt>@mime_version</tt>. When multipart messages are in
|
115
|
+
# use, <tt>@mime_version</tt> will be set to "1.0" if it is not set inside a method.
|
113
116
|
# * <tt>default_implicit_parts_order</tt> - When a message is built implicitly (i.e. multiple parts are assemble from templates
|
114
117
|
# which specify the content type in their filenames) this variable controls how the parts are ordered. Defaults to
|
115
118
|
# ["text/html", "text/enriched", "text/plain"]. Items that appear first in the array have higher priority in the mail client
|
@@ -150,15 +153,107 @@ module ActionMailer #:nodoc:
|
|
150
153
|
|
151
154
|
@@default_content_type = "text/plain"
|
152
155
|
cattr_accessor :default_content_type
|
156
|
+
|
157
|
+
@@default_mime_version = nil
|
158
|
+
cattr_accessor :default_mime_version
|
153
159
|
|
154
160
|
@@default_implicit_parts_order = [ "text/html", "text/enriched", "text/plain" ]
|
155
161
|
cattr_accessor :default_implicit_parts_order
|
156
162
|
|
157
|
-
|
158
|
-
|
159
|
-
|
163
|
+
# Specify the BCC addresses for the message
|
164
|
+
adv_attr_accessor :bcc
|
165
|
+
|
166
|
+
# Define the body of the message. This is either a Hash (in which case it
|
167
|
+
# specifies the variables to pass to the template when it is rendered),
|
168
|
+
# or a string, in which case it specifies the actual text of the message.
|
169
|
+
adv_attr_accessor :body
|
170
|
+
|
171
|
+
# Specify the CC addresses for the message.
|
172
|
+
adv_attr_accessor :cc
|
173
|
+
|
174
|
+
# Specify the charset to use for the message. This defaults to the
|
175
|
+
# +default_charset+ specified for ActionMailer::Base.
|
176
|
+
adv_attr_accessor :charset
|
177
|
+
|
178
|
+
# Specify the content type for the message. This defaults to <tt>text/plain</tt>
|
179
|
+
# in most cases, but can be automatically set in some situations.
|
180
|
+
adv_attr_accessor :content_type
|
181
|
+
|
182
|
+
# Specify the from address for the message.
|
183
|
+
adv_attr_accessor :from
|
184
|
+
|
185
|
+
# Specify additional headers to be added to the message.
|
186
|
+
adv_attr_accessor :headers
|
187
|
+
|
188
|
+
# Specify the order in which parts should be sorted, based on content-type.
|
189
|
+
# This defaults to the value for the +default_implicit_parts_order+.
|
190
|
+
adv_attr_accessor :implicit_parts_order
|
191
|
+
|
192
|
+
# Override the mailer name, which defaults to an inflected version of the
|
193
|
+
# mailer's class name. If you want to use a template in a non-standard
|
194
|
+
# location, you can use this to specify that location.
|
195
|
+
adv_attr_accessor :mailer_name
|
196
|
+
|
197
|
+
# Defaults to "1.0", but may be explicitly given if needed.
|
198
|
+
adv_attr_accessor :mime_version
|
199
|
+
|
200
|
+
# The recipient addresses for the message, either as a string (for a single
|
201
|
+
# address) or an array (for multiple addresses).
|
202
|
+
adv_attr_accessor :recipients
|
203
|
+
|
204
|
+
# The date on which the message was sent. If not set (the default), the
|
205
|
+
# header will be set by the delivery agent.
|
206
|
+
adv_attr_accessor :sent_on
|
207
|
+
|
208
|
+
# Specify the subject of the message.
|
209
|
+
adv_attr_accessor :subject
|
210
|
+
|
211
|
+
# Specify the template name to use for current message. This is the "base"
|
212
|
+
# template name, without the extension or directory, and may be used to
|
213
|
+
# have multiple mailer methods share the same template.
|
214
|
+
adv_attr_accessor :template
|
215
|
+
|
216
|
+
# The mail object instance referenced by this mailer.
|
217
|
+
attr_reader :mail
|
218
|
+
|
219
|
+
class << self
|
220
|
+
def method_missing(method_symbol, *parameters)#:nodoc:
|
221
|
+
case method_symbol.id2name
|
222
|
+
when /^create_([_a-z]\w*)/ then new($1, *parameters).mail
|
223
|
+
when /^deliver_([_a-z]\w*)/ then new($1, *parameters).deliver!
|
224
|
+
when "new" then nil
|
225
|
+
else super
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Receives a raw email, parses it into an email object, decodes it,
|
230
|
+
# instantiates a new mailer, and passes the email object to the mailer
|
231
|
+
# object's #receive method. If you want your mailer to be able to
|
232
|
+
# process incoming messages, you'll need to implement a #receive
|
233
|
+
# method that accepts the email object as a parameter:
|
234
|
+
#
|
235
|
+
# class MyMailer < ActionMailer::Base
|
236
|
+
# def receive(mail)
|
237
|
+
# ...
|
238
|
+
# end
|
239
|
+
# end
|
240
|
+
def receive(raw_email)
|
241
|
+
logger.info "Received mail:\n #{raw_email}" unless logger.nil?
|
242
|
+
mail = TMail::Mail.parse(raw_email)
|
243
|
+
mail.base64_decode
|
244
|
+
new.receive(mail)
|
245
|
+
end
|
160
246
|
|
161
|
-
|
247
|
+
# Deliver the given mail object directly. This can be used to deliver
|
248
|
+
# a preconstructed mail object, like:
|
249
|
+
#
|
250
|
+
# email = MyMailer.create_some_mail(parameters)
|
251
|
+
# email.set_some_obscure_header "frobnicate"
|
252
|
+
# MyMailer.deliver(email)
|
253
|
+
def deliver(mail)
|
254
|
+
new.deliver!(mail)
|
255
|
+
end
|
256
|
+
end
|
162
257
|
|
163
258
|
# Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer
|
164
259
|
# will be initialized according to the named method. If not, the mailer will
|
@@ -171,22 +266,15 @@ module ActionMailer #:nodoc:
|
|
171
266
|
# Initialize the mailer via the given +method_name+. The body will be
|
172
267
|
# rendered and a new TMail::Mail object created.
|
173
268
|
def create!(method_name, *parameters) #:nodoc:
|
174
|
-
|
175
|
-
@charset = @@default_charset.dup
|
176
|
-
@content_type = @@default_content_type.dup
|
177
|
-
@implicit_parts_order = @@default_implicit_parts_order.dup
|
178
|
-
@template = method_name
|
179
|
-
@parts = []
|
180
|
-
@headers = {}
|
181
|
-
@body = {}
|
182
|
-
|
269
|
+
initialize_defaults(method_name)
|
183
270
|
send(method_name, *parameters)
|
184
271
|
|
185
272
|
# If an explicit, textual body has not been set, we check assumptions.
|
186
273
|
unless String === @body
|
187
274
|
# First, we look to see if there are any likely templates that match,
|
188
275
|
# which include the content-type in their file name (i.e.,
|
189
|
-
# "the_template_file.text.html.rhtml", etc.).
|
276
|
+
# "the_template_file.text.html.rhtml", etc.). Only do this if parts
|
277
|
+
# have not already been specified manually.
|
190
278
|
if @parts.empty?
|
191
279
|
templates = Dir.glob("#{template_path}/#{@template}.*")
|
192
280
|
templates.each do |path|
|
@@ -198,6 +286,7 @@ module ActionMailer #:nodoc:
|
|
198
286
|
end
|
199
287
|
unless @parts.empty?
|
200
288
|
@content_type = "multipart/alternative"
|
289
|
+
@charset = nil
|
201
290
|
@parts = sort_parts(@parts, @implicit_parts_order)
|
202
291
|
end
|
203
292
|
end
|
@@ -219,32 +308,58 @@ module ActionMailer #:nodoc:
|
|
219
308
|
end
|
220
309
|
end
|
221
310
|
|
311
|
+
# If this is a multipart e-mail add the mime_version if it is not
|
312
|
+
# already set.
|
313
|
+
@mime_version ||= "1.0" if !@parts.empty?
|
314
|
+
|
222
315
|
# build the mail object itself
|
223
316
|
@mail = create_mail
|
224
317
|
end
|
225
318
|
|
226
|
-
# Delivers
|
227
|
-
#
|
228
|
-
|
229
|
-
|
319
|
+
# Delivers a TMail::Mail object. By default, it delivers the cached mail
|
320
|
+
# object (from the #create! method). If no cached mail object exists, and
|
321
|
+
# no alternate has been given as the parameter, this will fail.
|
322
|
+
def deliver!(mail = @mail)
|
323
|
+
raise "no mail object available for delivery!" unless mail
|
230
324
|
logger.info "Sent mail:\n #{mail.encoded}" unless logger.nil?
|
231
325
|
|
232
326
|
begin
|
233
|
-
send("perform_delivery_#{delivery_method}",
|
327
|
+
send("perform_delivery_#{delivery_method}", mail) if perform_deliveries
|
234
328
|
rescue Object => e
|
235
329
|
raise e if raise_delivery_errors
|
236
330
|
end
|
237
331
|
|
238
|
-
return
|
332
|
+
return mail
|
239
333
|
end
|
240
334
|
|
241
335
|
private
|
336
|
+
# Set up the default values for the various instance variables of this
|
337
|
+
# mailer. Subclasses may override this method to provide different
|
338
|
+
# defaults.
|
339
|
+
def initialize_defaults(method_name)
|
340
|
+
@bcc = @cc = @from = @recipients = @sent_on = @subject = nil
|
341
|
+
@charset = @@default_charset.dup
|
342
|
+
@content_type = @@default_content_type.dup
|
343
|
+
@implicit_parts_order = @@default_implicit_parts_order.dup
|
344
|
+
@template = method_name
|
345
|
+
@mailer_name = Inflector.underscore(self.class.name)
|
346
|
+
@parts = []
|
347
|
+
@headers = {}
|
348
|
+
@body = {}
|
349
|
+
@mime_version = @@default_mime_version.dup if @@default_mime_version
|
350
|
+
end
|
351
|
+
|
242
352
|
def render_message(method_name, body)
|
243
|
-
|
353
|
+
render :file => method_name, :body => body
|
244
354
|
end
|
245
|
-
|
355
|
+
|
356
|
+
def render(opts)
|
357
|
+
body = opts.delete(:body)
|
358
|
+
initialize_template_class(body).render(opts)
|
359
|
+
end
|
360
|
+
|
246
361
|
def template_path
|
247
|
-
template_root
|
362
|
+
"#{template_root}/#{mailer_name}"
|
248
363
|
end
|
249
364
|
|
250
365
|
def initialize_template_class(assigns)
|
@@ -288,6 +403,7 @@ module ActionMailer #:nodoc:
|
|
288
403
|
m.bcc = quote_address_if_necessary(bcc, charset) unless bcc.nil?
|
289
404
|
m.cc = quote_address_if_necessary(cc, charset) unless cc.nil?
|
290
405
|
|
406
|
+
m.mime_version = mime_version unless mime_version.nil?
|
291
407
|
m.date = sent_on.to_time rescue sent_on if sent_on
|
292
408
|
headers.each { |k, v| m[k] = v }
|
293
409
|
|
@@ -326,7 +442,7 @@ module ActionMailer #:nodoc:
|
|
326
442
|
|
327
443
|
def perform_delivery_sendmail(mail)
|
328
444
|
IO.popen("/usr/sbin/sendmail -i -t","w+") do |sm|
|
329
|
-
sm.print(mail.encoded)
|
445
|
+
sm.print(mail.encoded.gsub(/\r/, ''))
|
330
446
|
sm.flush
|
331
447
|
end
|
332
448
|
end
|
@@ -334,24 +450,5 @@ module ActionMailer #:nodoc:
|
|
334
450
|
def perform_delivery_test(mail)
|
335
451
|
deliveries << mail
|
336
452
|
end
|
337
|
-
|
338
|
-
class << self
|
339
|
-
def method_missing(method_symbol, *parameters)#:nodoc:
|
340
|
-
case method_symbol.id2name
|
341
|
-
when /^create_([_a-z]\w*)/ then new($1, *parameters).mail
|
342
|
-
when /^deliver_([_a-z]\w*)/ then new($1, *parameters).deliver!
|
343
|
-
when "new" then nil
|
344
|
-
else super
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
def receive(raw_email)
|
349
|
-
logger.info "Received mail:\n #{raw_email}" unless logger.nil?
|
350
|
-
mail = TMail::Mail.parse(raw_email)
|
351
|
-
mail.base64_decode
|
352
|
-
new.receive(mail)
|
353
|
-
end
|
354
|
-
|
355
|
-
end
|
356
453
|
end
|
357
454
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
module ActionMailer
|
1
|
+
module ActionMailer
|
2
2
|
module Helpers #:nodoc:
|
3
|
-
def self.append_features(base)
|
3
|
+
def self.append_features(base) #:nodoc:
|
4
4
|
super
|
5
5
|
|
6
6
|
# Initialize the base module to aggregate its helpers.
|
@@ -24,7 +24,7 @@ module ActionMailer #:nodoc:
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
module ClassMethods
|
27
|
+
module ClassMethods
|
28
28
|
# Makes all the (instance) methods in the helper module available to templates rendered through this controller.
|
29
29
|
# See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules
|
30
30
|
# available to the templates.
|
@@ -1,6 +1,8 @@
|
|
1
|
-
require '
|
1
|
+
require 'text/format'
|
2
2
|
|
3
|
-
module MailHelper
|
3
|
+
module MailHelper
|
4
|
+
# Uses Text::Format to take the text and format it, indented two spaces for
|
5
|
+
# each line, and wrapped at 72 columns.
|
4
6
|
def block_format(text)
|
5
7
|
formatted = text.split(/\n\r\n/).collect { |paragraph|
|
6
8
|
Text::Format.new(
|
@@ -14,4 +16,4 @@ module MailHelper#:nodoc:
|
|
14
16
|
|
15
17
|
formatted
|
16
18
|
end
|
17
|
-
end
|
19
|
+
end
|
data/lib/action_mailer/part.rb
CHANGED
@@ -3,13 +3,43 @@ require 'action_mailer/part_container'
|
|
3
3
|
require 'action_mailer/utils'
|
4
4
|
|
5
5
|
module ActionMailer
|
6
|
-
|
6
|
+
# Represents a subpart of an email message. It shares many similar
|
7
|
+
# attributes of ActionMailer::Base. Although you can create parts manually
|
8
|
+
# and add them to the #parts list of the mailer, it is easier
|
9
|
+
# to use the helper methods in ActionMailer::PartContainer.
|
10
|
+
class Part
|
7
11
|
include ActionMailer::AdvAttrAccessor
|
8
12
|
include ActionMailer::PartContainer
|
9
13
|
|
10
|
-
|
11
|
-
|
14
|
+
# Represents the body of the part, as a string. This should not be a
|
15
|
+
# Hash (like ActionMailer::Base), but if you want a template to be rendered
|
16
|
+
# into the body of a subpart you can do it with the mailer's #render method
|
17
|
+
# and assign the result here.
|
18
|
+
adv_attr_accessor :body
|
19
|
+
|
20
|
+
# Specify the charset for this subpart. By default, it will be the charset
|
21
|
+
# of the containing part or mailer.
|
22
|
+
adv_attr_accessor :charset
|
23
|
+
|
24
|
+
# The content disposition of this part, typically either "inline" or
|
25
|
+
# "attachment".
|
26
|
+
adv_attr_accessor :content_disposition
|
27
|
+
|
28
|
+
# The content type of the part.
|
29
|
+
adv_attr_accessor :content_type
|
30
|
+
|
31
|
+
# The filename to use for this subpart (usually for attachments).
|
32
|
+
adv_attr_accessor :filename
|
33
|
+
|
34
|
+
# Accessor for specifying additional headers to include with this part.
|
35
|
+
adv_attr_accessor :headers
|
36
|
+
|
37
|
+
# The transfer encoding to use for this subpart, like "base64" or
|
38
|
+
# "quoted-printable".
|
39
|
+
adv_attr_accessor :transfer_encoding
|
12
40
|
|
41
|
+
# Create a new part from the given +params+ hash. The valid params keys
|
42
|
+
# correspond to the accessors.
|
13
43
|
def initialize(params)
|
14
44
|
@content_type = params[:content_type]
|
15
45
|
@content_disposition = params[:disposition] || "inline"
|
@@ -21,6 +51,8 @@ module ActionMailer
|
|
21
51
|
@parts = []
|
22
52
|
end
|
23
53
|
|
54
|
+
# Convert the part to a mail object which can be included in the parts
|
55
|
+
# list of another mail object.
|
24
56
|
def to_mail(defaults)
|
25
57
|
part = TMail::Mail.new
|
26
58
|
|