mail 2.7.0.rc1 → 2.7.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +71 -98
  3. data/lib/mail.rb +1 -6
  4. data/lib/mail/attachments_list.rb +5 -2
  5. data/lib/mail/body.rb +39 -33
  6. data/lib/mail/check_delivery_params.rb +8 -6
  7. data/lib/mail/configuration.rb +2 -0
  8. data/lib/mail/elements/address.rb +19 -18
  9. data/lib/mail/encodings.rb +89 -31
  10. data/lib/mail/encodings/7bit.rb +5 -15
  11. data/lib/mail/encodings/8bit.rb +2 -21
  12. data/lib/mail/encodings/base64.rb +11 -12
  13. data/lib/mail/encodings/binary.rb +3 -22
  14. data/lib/mail/encodings/identity.rb +24 -0
  15. data/lib/mail/encodings/quoted_printable.rb +6 -6
  16. data/lib/mail/encodings/transfer_encoding.rb +38 -29
  17. data/lib/mail/encodings/unix_to_unix.rb +2 -1
  18. data/lib/mail/envelope.rb +1 -1
  19. data/lib/mail/field.rb +93 -61
  20. data/lib/mail/fields/bcc_field.rb +2 -2
  21. data/lib/mail/fields/cc_field.rb +1 -1
  22. data/lib/mail/fields/comments_field.rb +1 -1
  23. data/lib/mail/fields/common/common_address.rb +32 -7
  24. data/lib/mail/fields/common/common_field.rb +1 -10
  25. data/lib/mail/fields/content_description_field.rb +1 -1
  26. data/lib/mail/fields/content_disposition_field.rb +3 -3
  27. data/lib/mail/fields/content_id_field.rb +2 -2
  28. data/lib/mail/fields/content_location_field.rb +1 -1
  29. data/lib/mail/fields/content_transfer_encoding_field.rb +1 -1
  30. data/lib/mail/fields/content_type_field.rb +1 -1
  31. data/lib/mail/fields/date_field.rb +2 -3
  32. data/lib/mail/fields/from_field.rb +1 -1
  33. data/lib/mail/fields/in_reply_to_field.rb +1 -1
  34. data/lib/mail/fields/keywords_field.rb +1 -1
  35. data/lib/mail/fields/message_id_field.rb +1 -1
  36. data/lib/mail/fields/mime_version_field.rb +1 -1
  37. data/lib/mail/fields/optional_field.rb +4 -1
  38. data/lib/mail/fields/received_field.rb +1 -1
  39. data/lib/mail/fields/references_field.rb +1 -1
  40. data/lib/mail/fields/reply_to_field.rb +1 -1
  41. data/lib/mail/fields/resent_bcc_field.rb +1 -1
  42. data/lib/mail/fields/resent_cc_field.rb +1 -1
  43. data/lib/mail/fields/resent_date_field.rb +0 -1
  44. data/lib/mail/fields/resent_from_field.rb +1 -1
  45. data/lib/mail/fields/resent_message_id_field.rb +1 -1
  46. data/lib/mail/fields/resent_sender_field.rb +1 -1
  47. data/lib/mail/fields/resent_to_field.rb +1 -1
  48. data/lib/mail/fields/return_path_field.rb +1 -1
  49. data/lib/mail/fields/sender_field.rb +1 -1
  50. data/lib/mail/fields/subject_field.rb +1 -1
  51. data/lib/mail/fields/to_field.rb +1 -1
  52. data/lib/mail/fields/unstructured_field.rb +19 -2
  53. data/lib/mail/header.rb +9 -8
  54. data/lib/mail/mail.rb +2 -10
  55. data/lib/mail/matchers/has_sent_mail.rb +21 -1
  56. data/lib/mail/message.rb +64 -51
  57. data/lib/mail/multibyte.rb +14 -16
  58. data/lib/mail/multibyte/chars.rb +2 -1
  59. data/lib/mail/network.rb +1 -0
  60. data/lib/mail/network/delivery_methods/exim.rb +6 -10
  61. data/lib/mail/network/delivery_methods/logger_delivery.rb +37 -0
  62. data/lib/mail/network/delivery_methods/sendmail.rb +8 -4
  63. data/lib/mail/network/delivery_methods/smtp.rb +56 -55
  64. data/lib/mail/network/delivery_methods/smtp_connection.rb +9 -1
  65. data/lib/mail/network/retriever_methods/imap.rb +18 -5
  66. data/lib/mail/network/retriever_methods/pop3.rb +3 -1
  67. data/lib/mail/parser_tools.rb +15 -0
  68. data/lib/mail/parsers/address_lists_parser.rb +30462 -12597
  69. data/lib/mail/parsers/address_lists_parser.rl +18 -12
  70. data/lib/mail/parsers/content_disposition_parser.rb +405 -215
  71. data/lib/mail/parsers/content_disposition_parser.rl +11 -5
  72. data/lib/mail/parsers/content_location_parser.rb +443 -208
  73. data/lib/mail/parsers/content_location_parser.rl +9 -3
  74. data/lib/mail/parsers/content_transfer_encoding_parser.rb +180 -80
  75. data/lib/mail/parsers/content_transfer_encoding_parser.rl +8 -2
  76. data/lib/mail/parsers/content_type_parser.rb +436 -245
  77. data/lib/mail/parsers/content_type_parser.rl +12 -6
  78. data/lib/mail/parsers/date_time_parser.rb +172 -72
  79. data/lib/mail/parsers/date_time_parser.rl +10 -4
  80. data/lib/mail/parsers/envelope_from_parser.rb +2833 -1320
  81. data/lib/mail/parsers/envelope_from_parser.rl +9 -3
  82. data/lib/mail/parsers/message_ids_parser.rb +2325 -976
  83. data/lib/mail/parsers/message_ids_parser.rl +9 -3
  84. data/lib/mail/parsers/mime_version_parser.rb +164 -64
  85. data/lib/mail/parsers/mime_version_parser.rl +9 -3
  86. data/lib/mail/parsers/phrase_lists_parser.rb +582 -237
  87. data/lib/mail/parsers/phrase_lists_parser.rl +9 -3
  88. data/lib/mail/parsers/received_parser.rb +7036 -3004
  89. data/lib/mail/parsers/received_parser.rl +11 -5
  90. data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +1 -0
  91. data/lib/mail/parsers/rfc2045_content_type.rl +1 -0
  92. data/lib/mail/parsers/rfc2045_mime.rl +1 -0
  93. data/lib/mail/parsers/rfc2183_content_disposition.rl +1 -0
  94. data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  95. data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +7 -1
  96. data/lib/mail/parsers/rfc5322.rl +3 -1
  97. data/lib/mail/parsers/rfc5322_address.rl +3 -1
  98. data/lib/mail/parsers/rfc5322_date_time.rl +1 -0
  99. data/lib/mail/parsers/rfc5322_lexical_tokens.rl +9 -5
  100. data/lib/mail/part.rb +1 -1
  101. data/lib/mail/utilities.rb +44 -15
  102. data/lib/mail/version.rb +1 -1
  103. data/lib/mail/version_specific/ruby_1_8.rb +12 -1
  104. data/lib/mail/version_specific/ruby_1_9.rb +13 -1
  105. metadata +7 -13
  106. data/CHANGELOG.rdoc +0 -822
  107. data/CONTRIBUTING.md +0 -60
  108. data/Dependencies.txt +0 -1
  109. data/Gemfile +0 -11
  110. data/Rakefile +0 -23
  111. data/TODO.rdoc +0 -9
  112. data/lib/mail/multibyte/exceptions.rb +0 -9
@@ -56,15 +56,23 @@ module Mail
56
56
  #
57
57
  # ===Making an email via a block
58
58
  #
59
- # mail = Mail.new do
60
- # from 'mikel@test.lindsaar.net'
61
- # to 'you@test.lindsaar.net'
62
- # subject 'This is a test email'
63
- # body File.read('body.txt')
59
+ # mail = Mail.new do |m|
60
+ # m.from 'mikel@test.lindsaar.net'
61
+ # m.to 'you@test.lindsaar.net'
62
+ # m.subject 'This is a test email'
63
+ # m.body File.read('body.txt')
64
64
  # end
65
65
  #
66
66
  # mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...
67
67
  #
68
+ # If may also pass a block with no arguments, in which case it will
69
+ # be evaluated in the scope of the new message instance:
70
+ #
71
+ # mail = Mail.new do
72
+ # from 'mikel@test.lindsaar.net'
73
+ # # …
74
+ # end
75
+ #
68
76
  # ===Making an email via passing a string
69
77
  #
70
78
  # mail = Mail.new("To: mikel@test.lindsaar.net\r\nSubject: Hello\r\n\r\nHi there!")
@@ -129,8 +137,23 @@ module Mail
129
137
  init_with_string(args.flatten[0].to_s)
130
138
  end
131
139
 
140
+ # Support both builder styles:
141
+ #
142
+ # Mail.new do
143
+ # to 'recipient@example.com'
144
+ # end
145
+ #
146
+ # and
147
+ #
148
+ # Mail.new do |m|
149
+ # m.to 'recipient@example.com'
150
+ # end
132
151
  if block_given?
133
- instance_eval(&block)
152
+ if block.arity.zero? || (RUBY_VERSION < '1.9' && block.arity < 1)
153
+ instance_eval(&block)
154
+ else
155
+ yield self
156
+ end
134
157
  end
135
158
 
136
159
  self
@@ -213,7 +236,7 @@ module Mail
213
236
  self.default_charset = 'UTF-8'
214
237
 
215
238
  def register_for_delivery_notification(observer)
216
- $stderr.puts("Message#register_for_delivery_notification is deprecated, please call Mail.register_observer instead")
239
+ warn("Message#register_for_delivery_notification is deprecated, please call Mail.register_observer instead")
217
240
  Mail.register_observer(observer)
218
241
  end
219
242
 
@@ -225,7 +248,7 @@ module Mail
225
248
  Mail.inform_interceptors(self)
226
249
  end
227
250
 
228
- # Delivers an mail object.
251
+ # Delivers a mail object.
229
252
  #
230
253
  # Examples:
231
254
  #
@@ -1188,8 +1211,8 @@ module Mail
1188
1211
  def default( sym, val = nil )
1189
1212
  if val
1190
1213
  header[sym] = val
1191
- else
1192
- header[sym].default if header[sym]
1214
+ elsif field = header[sym]
1215
+ field.default
1193
1216
  end
1194
1217
  end
1195
1218
 
@@ -1235,14 +1258,13 @@ module Mail
1235
1258
  def body(value = nil)
1236
1259
  if value
1237
1260
  self.body = value
1238
- # add_encoding_to_body
1239
1261
  else
1240
1262
  process_body_raw if @body_raw
1241
1263
  @body
1242
1264
  end
1243
1265
  end
1244
1266
 
1245
- def body_encoding(value)
1267
+ def body_encoding(value = nil)
1246
1268
  if value.nil?
1247
1269
  body.encoding
1248
1270
  else
@@ -1251,7 +1273,7 @@ module Mail
1251
1273
  end
1252
1274
 
1253
1275
  def body_encoding=(value)
1254
- body.encoding = value
1276
+ body.encoding = value
1255
1277
  end
1256
1278
 
1257
1279
  # Returns the list of addresses this message should be sent to by
@@ -1415,7 +1437,7 @@ module Mail
1415
1437
  end
1416
1438
 
1417
1439
  def has_transfer_encoding? # :nodoc:
1418
- $stderr.puts(":has_transfer_encoding? is deprecated in Mail 1.4.3. Please use has_content_transfer_encoding?\n#{caller}")
1440
+ warn(":has_transfer_encoding? is deprecated in Mail 1.4.3. Please use has_content_transfer_encoding?\n#{caller}")
1419
1441
  has_content_transfer_encoding?
1420
1442
  end
1421
1443
 
@@ -1465,32 +1487,24 @@ module Mail
1465
1487
  # has not specified an encoding explicitly.
1466
1488
  if @defaulted_charset && !body.raw_source.ascii_only? && !self.attachment?
1467
1489
  warning = "Non US-ASCII detected and no charset defined.\nDefaulting to UTF-8, set your own if this is incorrect.\n"
1468
- $stderr.puts(warning)
1490
+ warn(warning)
1469
1491
  end
1470
1492
  header[:content_type].parameters['charset'] = @charset
1471
1493
  end
1472
1494
  end
1473
1495
 
1474
1496
  # Adds a content transfer encoding
1475
- #
1476
- # Otherwise raises a warning
1477
1497
  def add_content_transfer_encoding
1478
- if body.only_us_ascii?
1479
- header[:content_transfer_encoding] = '7bit'
1480
- else
1481
- warning = "Non US-ASCII detected and no content-transfer-encoding defined.\nDefaulting to 8bit, set your own if this is incorrect.\n"
1482
- $stderr.puts(warning)
1483
- header[:content_transfer_encoding] = '8bit'
1484
- end
1498
+ header[:content_transfer_encoding] ||= body.default_encoding
1485
1499
  end
1486
1500
 
1487
1501
  def add_transfer_encoding # :nodoc:
1488
- $stderr.puts(":add_transfer_encoding is deprecated in Mail 1.4.3. Please use add_content_transfer_encoding\n#{caller}")
1502
+ warn(":add_transfer_encoding is deprecated in Mail 1.4.3. Please use add_content_transfer_encoding\n#{caller}")
1489
1503
  add_content_transfer_encoding
1490
1504
  end
1491
1505
 
1492
1506
  def transfer_encoding # :nodoc:
1493
- $stderr.puts(":transfer_encoding is deprecated in Mail 1.4.3. Please use content_transfer_encoding\n#{caller}")
1507
+ warn(":transfer_encoding is deprecated in Mail 1.4.3. Please use content_transfer_encoding\n#{caller}")
1494
1508
  content_transfer_encoding
1495
1509
  end
1496
1510
 
@@ -1500,7 +1514,7 @@ module Mail
1500
1514
  end
1501
1515
 
1502
1516
  def message_content_type
1503
- $stderr.puts(":message_content_type is deprecated in Mail 1.4.3. Please use mime_type\n#{caller}")
1517
+ warn(":message_content_type is deprecated in Mail 1.4.3. Please use mime_type\n#{caller}")
1504
1518
  mime_type
1505
1519
  end
1506
1520
 
@@ -1532,7 +1546,7 @@ module Mail
1532
1546
 
1533
1547
  # Returns the content type parameters
1534
1548
  def mime_parameters
1535
- $stderr.puts(':mime_parameters is deprecated in Mail 1.4.3, please use :content_type_parameters instead')
1549
+ warn(':mime_parameters is deprecated in Mail 1.4.3, please use :content_type_parameters instead')
1536
1550
  content_type_parameters
1537
1551
  end
1538
1552
 
@@ -1780,9 +1794,6 @@ module Mail
1780
1794
  else
1781
1795
  basename = values[:filename]
1782
1796
  filedata = values
1783
- unless filedata[:content]
1784
- filedata = values.merge(:content=>File.open(values[:filename], 'rb') { |f| f.read })
1785
- end
1786
1797
  end
1787
1798
  self.attachments[basename] = filedata
1788
1799
  end
@@ -1808,7 +1819,7 @@ module Mail
1808
1819
  end
1809
1820
 
1810
1821
  def encode!
1811
- $stderr.puts("Deprecated in 1.1.0 in favour of :ready_to_send! as it is less confusing with encoding and decoding.")
1822
+ warn("Deprecated in 1.1.0 in favour of :ready_to_send! as it is less confusing with encoding and decoding.")
1812
1823
  ready_to_send!
1813
1824
  end
1814
1825
 
@@ -1824,16 +1835,13 @@ module Mail
1824
1835
  end
1825
1836
 
1826
1837
  def without_attachments!
1827
- return self unless has_attachments?
1828
-
1829
- parts.delete_if { |p| p.attachment? }
1830
- body_raw = if parts.empty?
1831
- ''
1832
- else
1833
- body.encoded
1834
- end
1838
+ if has_attachments?
1839
+ parts.delete_if { |p| p.attachment? }
1835
1840
 
1836
- @body = Mail::Body.new(body_raw)
1841
+ reencoded = parts.empty? ? '' : body.encoded(content_transfer_encoding)
1842
+ @body = nil # So the new parts won't be added to the existing body
1843
+ self.body = reencoded
1844
+ end
1837
1845
 
1838
1846
  self
1839
1847
  end
@@ -1993,7 +2001,7 @@ module Mail
1993
2001
 
1994
2002
  def raw_source=(value)
1995
2003
  value = value.dup.force_encoding(Encoding::BINARY) if RUBY_VERSION >= "1.9.1"
1996
- @raw_source = ::Mail::Utilities.to_crlf(value)
2004
+ @raw_source = value
1997
2005
  end
1998
2006
 
1999
2007
  # see comments to body=. We take data and process it lazily
@@ -2005,11 +2013,9 @@ module Mail
2005
2013
  @body_raw = nil
2006
2014
  add_encoding_to_body
2007
2015
  when @body && @body.multipart?
2008
- @body << Mail::Part.new(value)
2009
- add_encoding_to_body
2016
+ self.text_part = value
2010
2017
  else
2011
2018
  @body_raw = value
2012
- # process_body_raw
2013
2019
  end
2014
2020
  end
2015
2021
 
@@ -2024,7 +2030,7 @@ module Mail
2024
2030
 
2025
2031
  def set_envelope_header
2026
2032
  raw_string = raw_source.to_s
2027
- if match_data = raw_source.to_s.match(/\AFrom\s(#{TEXT}+)#{CRLF}/m)
2033
+ if match_data = raw_string.match(/\AFrom\s(#{TEXT}+)#{CRLF}/m)
2028
2034
  set_envelope(match_data[1])
2029
2035
  self.raw_source = raw_string.sub(match_data[0], "")
2030
2036
  end
@@ -2034,6 +2040,13 @@ module Mail
2034
2040
  body.split!(boundary)
2035
2041
  end
2036
2042
 
2043
+ def allowed_encodings
2044
+ case mime_type
2045
+ when 'message/rfc822'
2046
+ [Encodings::SevenBit, Encodings::EightBit, Encodings::Binary]
2047
+ end
2048
+ end
2049
+
2037
2050
  def add_encoding_to_body
2038
2051
  if has_content_transfer_encoding?
2039
2052
  @body.encoding = content_transfer_encoding
@@ -2041,11 +2054,11 @@ module Mail
2041
2054
  end
2042
2055
 
2043
2056
  def identify_and_set_transfer_encoding
2044
- if body && body.multipart?
2045
- self.content_transfer_encoding = @transport_encoding
2046
- else
2047
- self.content_transfer_encoding = body.get_best_encoding(@transport_encoding)
2048
- end
2057
+ if body && body.multipart?
2058
+ self.content_transfer_encoding = @transport_encoding
2059
+ else
2060
+ self.content_transfer_encoding = body.negotiate_best_encoding(@transport_encoding, allowed_encodings).to_s
2061
+ end
2049
2062
  end
2050
2063
 
2051
2064
  def add_required_fields
@@ -1,25 +1,23 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
+ require 'mail/multibyte/chars'
4
+
3
5
  module Mail #:nodoc:
4
6
  module Multibyte
5
- require 'mail/multibyte/exceptions'
6
- require 'mail/multibyte/chars'
7
- require 'mail/multibyte/unicode'
7
+ # Raised when a problem with the encoding was found.
8
+ class EncodingError < StandardError; end
8
9
 
9
- # The proxy class returned when calling mb_chars. You can use this accessor to configure your own proxy
10
- # class so you can support other encodings. See the Mail::Multibyte::Chars implementation for
11
- # an example how to do this.
12
- #
13
- # Example:
14
- # Mail::Multibyte.proxy_class = CharsForUTF32
15
- def self.proxy_class=(klass)
16
- @proxy_class = klass
10
+ class << self
11
+ # The proxy class returned when calling mb_chars. You can use this accessor to configure your own proxy
12
+ # class so you can support other encodings. See the Mail::Multibyte::Chars implementation for
13
+ # an example how to do this.
14
+ #
15
+ # Example:
16
+ # Mail::Multibyte.proxy_class = CharsForUTF32
17
+ attr_accessor :proxy_class
17
18
  end
18
19
 
19
- # Returns the current proxy class
20
- def self.proxy_class
21
- @proxy_class ||= Mail::Multibyte::Chars
22
- end
20
+ self.proxy_class = Mail::Multibyte::Chars
23
21
 
24
22
  if RUBY_VERSION >= "1.9"
25
23
  # == Multibyte proxy
@@ -91,4 +89,4 @@ module Mail #:nodoc:
91
89
  end
92
90
  end
93
91
 
94
- require 'mail/multibyte/utils'
92
+ require 'mail/multibyte/utils'
@@ -1,5 +1,6 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
+ require 'mail/multibyte/unicode'
3
4
 
4
5
  module Mail #:nodoc:
5
6
  module Multibyte #:nodoc:
@@ -40,7 +41,7 @@ module Mail #:nodoc:
40
41
  if RUBY_VERSION >= "1.9"
41
42
  # Creates a new Chars instance by wrapping _string_.
42
43
  def initialize(string)
43
- @wrapped_string = string
44
+ @wrapped_string = string.dup
44
45
  @wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
45
46
  end
46
47
  else
@@ -4,6 +4,7 @@ require 'mail/network/retriever_methods/base'
4
4
  module Mail
5
5
  register_autoload :SMTP, 'mail/network/delivery_methods/smtp'
6
6
  register_autoload :FileDelivery, 'mail/network/delivery_methods/file_delivery'
7
+ register_autoload :LoggerDelivery, 'mail/network/delivery_methods/logger_delivery'
7
8
  register_autoload :Sendmail, 'mail/network/delivery_methods/sendmail'
8
9
  register_autoload :Exim, 'mail/network/delivery_methods/exim'
9
10
  register_autoload :SMTPConnection, 'mail/network/delivery_methods/smtp_connection'
@@ -37,17 +37,13 @@ module Mail
37
37
  #
38
38
  # mail.deliver!
39
39
  class Exim < Sendmail
40
- def initialize(values)
41
- self.settings = { :location => '/usr/sbin/exim',
42
- :arguments => '-i -t' }.merge(values)
43
- end
40
+ DEFAULTS = {
41
+ :location => '/usr/sbin/exim',
42
+ :arguments => '-i -t'
43
+ }
44
44
 
45
- def self.call(path, arguments, destinations, mail)
46
- popen "#{path} #{arguments}" do |io|
47
- io.puts ::Mail::Utilities.to_lf(mail.encoded)
48
- io.flush
49
- end
45
+ def self.call(path, arguments, destinations, encoded_message)
46
+ super path, arguments, nil, encoded_message
50
47
  end
51
-
52
48
  end
53
49
  end
@@ -0,0 +1,37 @@
1
+ require 'mail/check_delivery_params'
2
+
3
+ module Mail
4
+ class LoggerDelivery
5
+ include Mail::CheckDeliveryParams
6
+
7
+ attr_reader :logger, :severity, :settings
8
+
9
+ def initialize(settings)
10
+ @settings = settings
11
+ @logger = settings.fetch(:logger) { default_logger }
12
+ @severity = derive_severity(settings[:severity])
13
+ end
14
+
15
+ def deliver!(mail)
16
+ Mail::CheckDeliveryParams.check(mail)
17
+ logger.log(severity) { mail.encoded }
18
+ end
19
+
20
+ private
21
+ def default_logger
22
+ require 'logger'
23
+ ::Logger.new($stdout)
24
+ end
25
+
26
+ def derive_severity(severity)
27
+ case severity
28
+ when nil
29
+ Logger::INFO
30
+ when Integer
31
+ severity
32
+ else
33
+ Logger.const_get(severity.to_s.upcase)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -38,17 +38,21 @@ module Mail
38
38
  #
39
39
  # mail.deliver!
40
40
  class Sendmail
41
+ DEFAULTS = {
42
+ :location => '/usr/sbin/sendmail',
43
+ :arguments => '-i'
44
+ }
45
+
41
46
  attr_accessor :settings
42
47
 
43
48
  def initialize(values)
44
- self.settings = { :location => '/usr/sbin/sendmail',
45
- :arguments => '-i' }.merge(values)
49
+ self.settings = self.class::DEFAULTS.merge(values)
46
50
  end
47
51
 
48
52
  def deliver!(mail)
49
53
  smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
50
54
 
51
- from = "-f #{self.class.shellquote(smtp_from)}"
55
+ from = "-f #{self.class.shellquote(smtp_from)}" if smtp_from
52
56
  to = smtp_to.map { |_to| self.class.shellquote(_to) }.join(' ')
53
57
 
54
58
  arguments = "#{settings[:arguments]} #{from} --"
@@ -57,7 +61,7 @@ module Mail
57
61
 
58
62
  def self.call(path, arguments, destinations, encoded_message)
59
63
  popen "#{path} #{arguments} #{destinations}" do |io|
60
- io.puts ::Mail::Utilities.to_lf(encoded_message)
64
+ io.puts ::Mail::Utilities.binary_unsafe_to_lf(encoded_message)
61
65
  io.flush
62
66
  end
63
67
  end
@@ -76,73 +76,74 @@ module Mail
76
76
  class SMTP
77
77
  attr_accessor :settings
78
78
 
79
+ DEFAULTS = {
80
+ :address => 'localhost',
81
+ :port => 25,
82
+ :domain => 'localhost.localdomain',
83
+ :user_name => nil,
84
+ :password => nil,
85
+ :authentication => nil,
86
+ :enable_starttls => nil,
87
+ :enable_starttls_auto => true,
88
+ :openssl_verify_mode => nil,
89
+ :ssl => nil,
90
+ :tls => nil,
91
+ :open_timeout => nil,
92
+ :read_timeout => nil
93
+ }
94
+
79
95
  def initialize(values)
80
- self.settings = { :address => "localhost",
81
- :port => 25,
82
- :domain => 'localhost.localdomain',
83
- :user_name => nil,
84
- :password => nil,
85
- :authentication => nil,
86
- :enable_starttls => nil,
87
- :enable_starttls_auto => true,
88
- :openssl_verify_mode => nil,
89
- :ssl => nil,
90
- :tls => nil,
91
- :open_timeout => nil,
92
- :read_timeout => nil
93
- }.merge!(values)
96
+ self.settings = DEFAULTS.merge(values)
94
97
  end
95
98
 
96
- # Send the message via SMTP.
97
- # The from and to attributes are optional. If not set, they are retrieve from the Message.
98
99
  def deliver!(mail)
99
- smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
100
-
101
- smtp = Net::SMTP.new(settings[:address], settings[:port])
102
- if settings[:tls] || settings[:ssl]
103
- if smtp.respond_to?(:enable_tls)
104
- smtp.enable_tls(ssl_context)
105
- end
106
- elsif settings[:enable_starttls]
107
- if smtp.respond_to?(:enable_starttls)
108
- smtp.enable_starttls(ssl_context)
109
- end
110
- elsif settings[:enable_starttls_auto]
111
- if smtp.respond_to?(:enable_starttls_auto)
112
- smtp.enable_starttls_auto(ssl_context)
113
- end
114
- end
115
- smtp.open_timeout = settings[:open_timeout] if settings[:open_timeout]
116
- smtp.read_timeout = settings[:read_timeout] if settings[:read_timeout]
117
-
118
- response = nil
119
- smtp.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication]) do |smtp_obj|
120
- response = smtp_obj.sendmail(message, smtp_from, smtp_to)
100
+ response = start_smtp_session do |smtp|
101
+ Mail::SMTPConnection.new(:connection => smtp, :return_response => true).deliver!(mail)
121
102
  end
122
103
 
123
- if settings[:return_response]
124
- response
125
- else
126
- self
127
- end
104
+ settings[:return_response] ? response : self
128
105
  end
129
106
 
130
107
  private
108
+ def start_smtp_session(&block)
109
+ build_smtp_session.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication], &block)
110
+ end
131
111
 
132
- # Allow SSL context to be configured via settings, for Ruby >= 1.9
133
- # Just returns openssl verify mode for Ruby 1.8.x
134
- def ssl_context
135
- openssl_verify_mode = settings[:openssl_verify_mode]
112
+ def build_smtp_session
113
+ Net::SMTP.new(settings[:address], settings[:port]).tap do |smtp|
114
+ if settings[:tls] || settings[:ssl]
115
+ if smtp.respond_to?(:enable_tls)
116
+ smtp.enable_tls(ssl_context)
117
+ end
118
+ elsif settings[:enable_starttls]
119
+ if smtp.respond_to?(:enable_starttls)
120
+ smtp.enable_starttls(ssl_context)
121
+ end
122
+ elsif settings[:enable_starttls_auto]
123
+ if smtp.respond_to?(:enable_starttls_auto)
124
+ smtp.enable_starttls_auto(ssl_context)
125
+ end
126
+ end
136
127
 
137
- if openssl_verify_mode.kind_of?(String)
138
- openssl_verify_mode = OpenSSL::SSL.const_get("VERIFY_#{openssl_verify_mode.upcase}")
128
+ smtp.open_timeout = settings[:open_timeout] if settings[:open_timeout]
129
+ smtp.read_timeout = settings[:read_timeout] if settings[:read_timeout]
130
+ end
139
131
  end
140
132
 
141
- context = Net::SMTP.default_ssl_context
142
- context.verify_mode = openssl_verify_mode if openssl_verify_mode
143
- context.ca_path = settings[:ca_path] if settings[:ca_path]
144
- context.ca_file = settings[:ca_file] if settings[:ca_file]
145
- context
146
- end
133
+ # Allow SSL context to be configured via settings, for Ruby >= 1.9
134
+ # Just returns openssl verify mode for Ruby 1.8.x
135
+ def ssl_context
136
+ openssl_verify_mode = settings[:openssl_verify_mode]
137
+
138
+ if openssl_verify_mode.kind_of?(String)
139
+ openssl_verify_mode = OpenSSL::SSL.const_get("VERIFY_#{openssl_verify_mode.upcase}")
140
+ end
141
+
142
+ context = Net::SMTP.default_ssl_context
143
+ context.verify_mode = openssl_verify_mode if openssl_verify_mode
144
+ context.ca_path = settings[:ca_path] if settings[:ca_path]
145
+ context.ca_file = settings[:ca_file] if settings[:ca_file]
146
+ context
147
+ end
147
148
  end
148
149
  end