mail 2.7.0.rc1 → 2.7.0.rc2

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 (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