mail 2.6.3 → 2.7.0

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 (178) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +91 -79
  4. data/lib/mail/attachments_list.rb +11 -5
  5. data/lib/mail/body.rb +46 -39
  6. data/lib/mail/check_delivery_params.rb +50 -10
  7. data/lib/mail/configuration.rb +3 -0
  8. data/lib/mail/constants.rb +4 -2
  9. data/lib/mail/core_extensions/smtp.rb +20 -16
  10. data/lib/mail/core_extensions/string.rb +1 -30
  11. data/lib/mail/elements/address.rb +43 -32
  12. data/lib/mail/elements/address_list.rb +11 -18
  13. data/lib/mail/elements/content_disposition_element.rb +9 -15
  14. data/lib/mail/elements/content_location_element.rb +8 -12
  15. data/lib/mail/elements/content_transfer_encoding_element.rb +6 -10
  16. data/lib/mail/elements/content_type_element.rb +9 -19
  17. data/lib/mail/elements/date_time_element.rb +7 -14
  18. data/lib/mail/elements/envelope_from_element.rb +15 -21
  19. data/lib/mail/elements/message_ids_element.rb +12 -14
  20. data/lib/mail/elements/mime_version_element.rb +7 -14
  21. data/lib/mail/elements/phrase_list.rb +7 -9
  22. data/lib/mail/elements/received_element.rb +10 -15
  23. data/lib/mail/elements.rb +1 -0
  24. data/lib/mail/encodings/7bit.rb +6 -15
  25. data/lib/mail/encodings/8bit.rb +5 -18
  26. data/lib/mail/encodings/base64.rb +15 -10
  27. data/lib/mail/encodings/binary.rb +4 -22
  28. data/lib/mail/encodings/identity.rb +24 -0
  29. data/lib/mail/encodings/quoted_printable.rb +13 -7
  30. data/lib/mail/encodings/transfer_encoding.rb +47 -28
  31. data/lib/mail/encodings/unix_to_unix.rb +3 -1
  32. data/lib/mail/encodings.rb +114 -60
  33. data/lib/mail/envelope.rb +2 -1
  34. data/lib/mail/field.rb +112 -62
  35. data/lib/mail/field_list.rb +1 -0
  36. data/lib/mail/fields/bcc_field.rb +17 -5
  37. data/lib/mail/fields/cc_field.rb +2 -2
  38. data/lib/mail/fields/comments_field.rb +2 -1
  39. data/lib/mail/fields/common/address_container.rb +3 -2
  40. data/lib/mail/fields/common/common_address.rb +40 -14
  41. data/lib/mail/fields/common/common_date.rb +2 -1
  42. data/lib/mail/fields/common/common_field.rb +5 -11
  43. data/lib/mail/fields/common/common_message_id.rb +3 -2
  44. data/lib/mail/fields/common/parameter_hash.rb +2 -1
  45. data/lib/mail/fields/content_description_field.rb +2 -1
  46. data/lib/mail/fields/content_disposition_field.rb +14 -13
  47. data/lib/mail/fields/content_id_field.rb +5 -4
  48. data/lib/mail/fields/content_location_field.rb +3 -2
  49. data/lib/mail/fields/content_transfer_encoding_field.rb +3 -2
  50. data/lib/mail/fields/content_type_field.rb +6 -10
  51. data/lib/mail/fields/date_field.rb +4 -4
  52. data/lib/mail/fields/from_field.rb +2 -2
  53. data/lib/mail/fields/in_reply_to_field.rb +2 -1
  54. data/lib/mail/fields/keywords_field.rb +3 -3
  55. data/lib/mail/fields/message_id_field.rb +3 -2
  56. data/lib/mail/fields/mime_version_field.rb +4 -3
  57. data/lib/mail/fields/optional_field.rb +5 -1
  58. data/lib/mail/fields/received_field.rb +5 -4
  59. data/lib/mail/fields/references_field.rb +2 -1
  60. data/lib/mail/fields/reply_to_field.rb +2 -2
  61. data/lib/mail/fields/resent_bcc_field.rb +2 -2
  62. data/lib/mail/fields/resent_cc_field.rb +2 -2
  63. data/lib/mail/fields/resent_date_field.rb +2 -2
  64. data/lib/mail/fields/resent_from_field.rb +2 -2
  65. data/lib/mail/fields/resent_message_id_field.rb +2 -1
  66. data/lib/mail/fields/resent_sender_field.rb +2 -2
  67. data/lib/mail/fields/resent_to_field.rb +2 -2
  68. data/lib/mail/fields/return_path_field.rb +2 -2
  69. data/lib/mail/fields/sender_field.rb +2 -2
  70. data/lib/mail/fields/structured_field.rb +1 -0
  71. data/lib/mail/fields/subject_field.rb +2 -1
  72. data/lib/mail/fields/to_field.rb +2 -2
  73. data/lib/mail/fields/unstructured_field.rb +25 -7
  74. data/lib/mail/fields.rb +1 -0
  75. data/lib/mail/header.rb +15 -12
  76. data/lib/mail/indifferent_hash.rb +1 -0
  77. data/lib/mail/mail.rb +3 -10
  78. data/lib/mail/matchers/attachment_matchers.rb +29 -0
  79. data/lib/mail/matchers/has_sent_mail.rb +51 -7
  80. data/lib/mail/message.rb +91 -85
  81. data/lib/mail/multibyte/chars.rb +32 -30
  82. data/lib/mail/multibyte/unicode.rb +21 -16
  83. data/lib/mail/multibyte/utils.rb +1 -0
  84. data/lib/mail/multibyte.rb +65 -15
  85. data/lib/mail/network/delivery_methods/exim.rb +7 -10
  86. data/lib/mail/network/delivery_methods/file_delivery.rb +5 -8
  87. data/lib/mail/network/delivery_methods/logger_delivery.rb +37 -0
  88. data/lib/mail/network/delivery_methods/sendmail.rb +17 -11
  89. data/lib/mail/network/delivery_methods/smtp.rb +60 -53
  90. data/lib/mail/network/delivery_methods/smtp_connection.rb +11 -6
  91. data/lib/mail/network/delivery_methods/test_mailer.rb +6 -8
  92. data/lib/mail/network/retriever_methods/base.rb +1 -0
  93. data/lib/mail/network/retriever_methods/imap.rb +19 -5
  94. data/lib/mail/network/retriever_methods/pop3.rb +4 -1
  95. data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
  96. data/lib/mail/network.rb +2 -0
  97. data/lib/mail/parser_tools.rb +15 -0
  98. data/lib/mail/parsers/address_lists_parser.rb +33187 -112
  99. data/lib/mail/parsers/address_lists_parser.rl +172 -0
  100. data/lib/mail/parsers/content_disposition_parser.rb +889 -55
  101. data/lib/mail/parsers/content_disposition_parser.rl +82 -0
  102. data/lib/mail/parsers/content_location_parser.rb +801 -23
  103. data/lib/mail/parsers/content_location_parser.rl +71 -0
  104. data/lib/mail/parsers/content_transfer_encoding_parser.rb +511 -22
  105. data/lib/mail/parsers/content_transfer_encoding_parser.rl +64 -0
  106. data/lib/mail/parsers/content_type_parser.rb +1033 -54
  107. data/lib/mail/parsers/content_type_parser.rl +83 -0
  108. data/lib/mail/parsers/date_time_parser.rb +875 -25
  109. data/lib/mail/parsers/date_time_parser.rl +62 -0
  110. data/lib/mail/parsers/envelope_from_parser.rb +3565 -36
  111. data/lib/mail/parsers/envelope_from_parser.rl +82 -0
  112. data/lib/mail/parsers/message_ids_parser.rb +2844 -25
  113. data/lib/mail/parsers/message_ids_parser.rl +82 -0
  114. data/lib/mail/parsers/mime_version_parser.rb +494 -26
  115. data/lib/mail/parsers/mime_version_parser.rl +61 -0
  116. data/lib/mail/parsers/phrase_lists_parser.rb +876 -18
  117. data/lib/mail/parsers/phrase_lists_parser.rl +83 -0
  118. data/lib/mail/parsers/received_parser.rb +8744 -37
  119. data/lib/mail/parsers/received_parser.rl +84 -0
  120. data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
  121. data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
  122. data/lib/mail/parsers/rfc2045_mime.rl +16 -0
  123. data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
  124. data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  125. data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
  126. data/lib/mail/parsers/rfc5322.rl +59 -0
  127. data/lib/mail/parsers/rfc5322_address.rl +72 -0
  128. data/lib/mail/parsers/{ragel/date_time.rl → rfc5322_date_time.rl} +8 -1
  129. data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
  130. data/lib/mail/parsers.rb +17 -24
  131. data/lib/mail/part.rb +6 -3
  132. data/lib/mail/parts_list.rb +31 -14
  133. data/lib/mail/utilities.rb +107 -8
  134. data/lib/mail/values/unicode_tables.dat +0 -0
  135. data/lib/mail/version.rb +3 -2
  136. data/lib/mail/version_specific/ruby_1_8.rb +50 -6
  137. data/lib/mail/version_specific/ruby_1_9.rb +103 -18
  138. data/lib/mail.rb +5 -12
  139. metadata +33 -57
  140. data/CHANGELOG.rdoc +0 -759
  141. data/CONTRIBUTING.md +0 -60
  142. data/Dependencies.txt +0 -2
  143. data/Gemfile +0 -15
  144. data/Rakefile +0 -29
  145. data/TODO.rdoc +0 -9
  146. data/lib/mail/core_extensions/nil.rb +0 -19
  147. data/lib/mail/core_extensions/object.rb +0 -13
  148. data/lib/mail/core_extensions/string/access.rb +0 -145
  149. data/lib/mail/core_extensions/string/multibyte.rb +0 -78
  150. data/lib/mail/multibyte/exceptions.rb +0 -8
  151. data/lib/mail/parsers/ragel/common.rl +0 -185
  152. data/lib/mail/parsers/ragel/parser_info.rb +0 -61
  153. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +0 -14864
  154. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +0 -37
  155. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +0 -751
  156. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +0 -37
  157. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +0 -614
  158. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +0 -37
  159. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +0 -447
  160. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +0 -37
  161. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +0 -825
  162. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +0 -37
  163. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +0 -817
  164. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +0 -37
  165. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +0 -2149
  166. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +0 -37
  167. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +0 -1570
  168. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +0 -37
  169. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +0 -440
  170. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +0 -37
  171. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +0 -564
  172. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +0 -37
  173. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +0 -51
  174. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +0 -5144
  175. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +0 -37
  176. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +0 -37
  177. data/lib/mail/parsers/ragel/ruby.rb +0 -40
  178. data/lib/mail/parsers/ragel.rb +0 -17
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ module Mail
3
+ module Matchers
4
+ def any_attachment
5
+ AnyAttachmentMatcher.new
6
+ end
7
+
8
+ def an_attachment_with_filename(filename)
9
+ AttachmentFilenameMatcher.new(filename)
10
+ end
11
+
12
+ class AnyAttachmentMatcher
13
+ def ===(other)
14
+ other.attachment?
15
+ end
16
+ end
17
+
18
+ class AttachmentFilenameMatcher
19
+ attr_reader :filename
20
+ def initialize(filename)
21
+ @filename = filename
22
+ end
23
+
24
+ def ===(other)
25
+ other.attachment? && other.filename == filename
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Mail
2
3
  module Matchers
3
4
  def have_sent_email
@@ -42,15 +43,25 @@ module Mail
42
43
 
43
44
  def bcc(recipient_or_list)
44
45
  @blind_copy_recipients ||= []
46
+ @blind_copy_recipients.concat(Array(recipient_or_list))
47
+ self
48
+ end
45
49
 
46
- if recipient_or_list.kind_of?(Array)
47
- @blind_copy_recipients += recipient_or_list
48
- else
49
- @blind_copy_recipients << recipient_or_list
50
- end
50
+ def with_attachments(attachments)
51
+ @attachments ||= []
52
+ @attachments.concat(Array(attachments))
51
53
  self
52
54
  end
53
55
 
56
+ def with_no_attachments
57
+ @having_attachments = false
58
+ self
59
+ end
60
+
61
+ def with_any_attachments
62
+ @having_attachments = true
63
+ self
64
+ end
54
65
 
55
66
  def with_subject(subject)
56
67
  @subject = subject
@@ -72,6 +83,16 @@ module Mail
72
83
  self
73
84
  end
74
85
 
86
+ def with_html(body)
87
+ @html_part_body = body
88
+ self
89
+ end
90
+
91
+ def with_text(body)
92
+ @text_part_body = body
93
+ self
94
+ end
95
+
75
96
  def description
76
97
  result = "send a matching email"
77
98
  result
@@ -95,8 +116,10 @@ module Mail
95
116
 
96
117
  def filter_matched_deliveries(deliveries)
97
118
  candidate_deliveries = deliveries
98
-
99
- %w(sender recipients copy_recipients blind_copy_recipients subject subject_matcher body body_matcher).each do |modifier_name|
119
+ modifiers =
120
+ %w(sender recipients copy_recipients blind_copy_recipients subject
121
+ subject_matcher body body_matcher html_part_body text_part_body having_attachments attachments)
122
+ modifiers.each do |modifier_name|
100
123
  next unless instance_variable_defined?("@#{modifier_name}")
101
124
  candidate_deliveries = candidate_deliveries.select{|matching_delivery| self.send("matches_on_#{modifier_name}?", matching_delivery)}
102
125
  end
@@ -128,6 +151,17 @@ module Mail
128
151
  @subject_matcher.match delivery.subject
129
152
  end
130
153
 
154
+ def matches_on_having_attachments?(delivery)
155
+ @having_attachments && delivery.attachments.any? ||
156
+ (!@having_attachments && delivery.attachments.none?)
157
+ end
158
+
159
+ def matches_on_attachments?(delivery)
160
+ @attachments.each_with_index.inject( true ) do |sent_attachments, (attachment, index)|
161
+ sent_attachments &&= (attachment === delivery.attachments[index])
162
+ end
163
+ end
164
+
131
165
  def matches_on_body?(delivery)
132
166
  delivery.body == @body
133
167
  end
@@ -136,6 +170,14 @@ module Mail
136
170
  @body_matcher.match delivery.body.raw_source
137
171
  end
138
172
 
173
+ def matches_on_html_part_body?(delivery)
174
+ delivery.html_part.body == @html_part_body
175
+ end
176
+
177
+ def matches_on_text_part_body?(delivery)
178
+ delivery.text_part.body == @text_part_body
179
+ end
180
+
139
181
  def explain_expectations
140
182
  result = ''
141
183
  result += "from #{@sender} " if instance_variable_defined?('@sender')
@@ -146,6 +188,8 @@ module Mail
146
188
  result += "with subject matching \"#{@subject_matcher}\" " if instance_variable_defined?('@subject_matcher')
147
189
  result += "with body \"#{@body}\" " if instance_variable_defined?('@body')
148
190
  result += "with body matching \"#{@body_matcher}\" " if instance_variable_defined?('@body_matcher')
191
+ result += "with a text part matching \"#{@text_part_body}\" " if instance_variable_defined?('@text_part_body')
192
+ result += "with an HTML part matching \"#{@html_part_body}\" " if instance_variable_defined?('@html_part_body')
149
193
  result
150
194
  end
151
195
 
data/lib/mail/message.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
  require "yaml"
3
4
 
4
5
  module Mail
@@ -55,15 +56,23 @@ module Mail
55
56
  #
56
57
  # ===Making an email via a block
57
58
  #
58
- # mail = Mail.new do
59
- # from 'mikel@test.lindsaar.net'
60
- # to 'you@test.lindsaar.net'
61
- # subject 'This is a test email'
62
- # 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')
63
64
  # end
64
65
  #
65
66
  # mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...
66
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
+ #
67
76
  # ===Making an email via passing a string
68
77
  #
69
78
  # mail = Mail.new("To: mikel@test.lindsaar.net\r\nSubject: Hello\r\n\r\nHi there!")
@@ -128,8 +137,23 @@ module Mail
128
137
  init_with_string(args.flatten[0].to_s)
129
138
  end
130
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
131
151
  if block_given?
132
- 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
133
157
  end
134
158
 
135
159
  self
@@ -212,7 +236,7 @@ module Mail
212
236
  self.default_charset = 'UTF-8'
213
237
 
214
238
  def register_for_delivery_notification(observer)
215
- 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")
216
240
  Mail.register_observer(observer)
217
241
  end
218
242
 
@@ -224,7 +248,7 @@ module Mail
224
248
  Mail.inform_interceptors(self)
225
249
  end
226
250
 
227
- # Delivers an mail object.
251
+ # Delivers a mail object.
228
252
  #
229
253
  # Examples:
230
254
  #
@@ -359,13 +383,8 @@ module Mail
359
383
  if self.message_id && other.message_id
360
384
  self.encoded == other.encoded
361
385
  else
362
- self_message_id, other_message_id = self.message_id, other.message_id
363
- begin
364
- self.message_id, other.message_id = '<temp@test>', '<temp@test>'
365
- self.encoded == other.encoded
366
- ensure
367
- self.message_id, other.message_id = self_message_id, other_message_id
368
- end
386
+ dup.tap { |m| m.message_id = '<temp@test>' }.encoded ==
387
+ other.dup.tap { |m| m.message_id = '<temp@test>' }.encoded
369
388
  end
370
389
  end
371
390
 
@@ -1192,8 +1211,8 @@ module Mail
1192
1211
  def default( sym, val = nil )
1193
1212
  if val
1194
1213
  header[sym] = val
1195
- else
1196
- header[sym].default if header[sym]
1214
+ elsif field = header[sym]
1215
+ field.default
1197
1216
  end
1198
1217
  end
1199
1218
 
@@ -1239,14 +1258,13 @@ module Mail
1239
1258
  def body(value = nil)
1240
1259
  if value
1241
1260
  self.body = value
1242
- # add_encoding_to_body
1243
1261
  else
1244
1262
  process_body_raw if @body_raw
1245
1263
  @body
1246
1264
  end
1247
1265
  end
1248
1266
 
1249
- def body_encoding(value)
1267
+ def body_encoding(value = nil)
1250
1268
  if value.nil?
1251
1269
  body.encoding
1252
1270
  else
@@ -1255,7 +1273,7 @@ module Mail
1255
1273
  end
1256
1274
 
1257
1275
  def body_encoding=(value)
1258
- body.encoding = value
1276
+ body.encoding = value
1259
1277
  end
1260
1278
 
1261
1279
  # Returns the list of addresses this message should be sent to by
@@ -1415,11 +1433,11 @@ module Mail
1415
1433
  end
1416
1434
 
1417
1435
  def has_content_transfer_encoding?
1418
- header[:content_transfer_encoding] && header[:content_transfer_encoding].errors.blank?
1436
+ header[:content_transfer_encoding] && Utilities.blank?(header[:content_transfer_encoding].errors)
1419
1437
  end
1420
1438
 
1421
1439
  def has_transfer_encoding? # :nodoc:
1422
- 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}")
1423
1441
  has_content_transfer_encoding?
1424
1442
  end
1425
1443
 
@@ -1467,34 +1485,26 @@ module Mail
1467
1485
  if !body.empty?
1468
1486
  # Only give a warning if this isn't an attachment, has non US-ASCII and the user
1469
1487
  # has not specified an encoding explicitly.
1470
- if @defaulted_charset && body.raw_source.not_ascii_only? && !self.attachment?
1488
+ if @defaulted_charset && !body.raw_source.ascii_only? && !self.attachment?
1471
1489
  warning = "Non US-ASCII detected and no charset defined.\nDefaulting to UTF-8, set your own if this is incorrect.\n"
1472
- STDERR.puts(warning)
1490
+ warn(warning)
1473
1491
  end
1474
1492
  header[:content_type].parameters['charset'] = @charset
1475
1493
  end
1476
1494
  end
1477
1495
 
1478
1496
  # Adds a content transfer encoding
1479
- #
1480
- # Otherwise raises a warning
1481
1497
  def add_content_transfer_encoding
1482
- if body.only_us_ascii?
1483
- header[:content_transfer_encoding] = '7bit'
1484
- else
1485
- warning = "Non US-ASCII detected and no content-transfer-encoding defined.\nDefaulting to 8bit, set your own if this is incorrect.\n"
1486
- STDERR.puts(warning)
1487
- header[:content_transfer_encoding] = '8bit'
1488
- end
1498
+ header[:content_transfer_encoding] ||= body.default_encoding
1489
1499
  end
1490
1500
 
1491
1501
  def add_transfer_encoding # :nodoc:
1492
- 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}")
1493
1503
  add_content_transfer_encoding
1494
1504
  end
1495
1505
 
1496
1506
  def transfer_encoding # :nodoc:
1497
- 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}")
1498
1508
  content_transfer_encoding
1499
1509
  end
1500
1510
 
@@ -1504,7 +1514,7 @@ module Mail
1504
1514
  end
1505
1515
 
1506
1516
  def message_content_type
1507
- 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}")
1508
1518
  mime_type
1509
1519
  end
1510
1520
 
@@ -1536,7 +1546,7 @@ module Mail
1536
1546
 
1537
1547
  # Returns the content type parameters
1538
1548
  def mime_parameters
1539
- 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')
1540
1550
  content_type_parameters
1541
1551
  end
1542
1552
 
@@ -1562,7 +1572,14 @@ module Mail
1562
1572
 
1563
1573
  # returns the part in a multipart/report email that has the content-type delivery-status
1564
1574
  def delivery_status_part
1565
- @delivery_stats_part ||= parts.select { |p| p.delivery_status_report_part? }.first
1575
+ unless defined? @delivery_status_part
1576
+ @delivery_status_part =
1577
+ if delivery_status_report?
1578
+ parts.detect(&:delivery_status_report_part?)
1579
+ end
1580
+ end
1581
+
1582
+ @delivery_status_part
1566
1583
  end
1567
1584
 
1568
1585
  def bounced?
@@ -1669,6 +1686,8 @@ module Mail
1669
1686
  def html_part=(msg)
1670
1687
  # Assign the html part and set multipart/alternative if there's a text part.
1671
1688
  if msg
1689
+ msg = Mail::Part.new(:body => msg) unless msg.kind_of?(Mail::Message)
1690
+
1672
1691
  @html_part = msg
1673
1692
  @html_part.content_type = 'text/html' unless @html_part.has_content_type?
1674
1693
  add_multipart_alternate_header if text_part
@@ -1691,6 +1710,8 @@ module Mail
1691
1710
  def text_part=(msg)
1692
1711
  # Assign the text part and set multipart/alternative if there's an html part.
1693
1712
  if msg
1713
+ msg = Mail::Part.new(:body => msg) unless msg.kind_of?(Mail::Message)
1714
+
1694
1715
  @text_part = msg
1695
1716
  @text_part.content_type = 'text/plain' unless @text_part.has_content_type?
1696
1717
  add_multipart_alternate_header if html_part
@@ -1709,7 +1730,7 @@ module Mail
1709
1730
 
1710
1731
  # Adds a part to the parts list or creates the part list
1711
1732
  def add_part(part)
1712
- if !body.multipart? && !self.body.decoded.blank?
1733
+ if !body.multipart? && !Utilities.blank?(self.body.decoded)
1713
1734
  @text_part = Mail::Part.new('Content-Type: text/plain;')
1714
1735
  @text_part.body = body.decoded
1715
1736
  self.body << @text_part
@@ -1765,14 +1786,14 @@ module Mail
1765
1786
  #
1766
1787
  # See also #attachments
1767
1788
  def add_file(values)
1768
- convert_to_multipart unless self.multipart? || self.body.decoded.blank?
1789
+ convert_to_multipart unless self.multipart? || Utilities.blank?(self.body.decoded)
1769
1790
  add_multipart_mixed_header
1770
1791
  if values.is_a?(String)
1771
1792
  basename = File.basename(values)
1772
1793
  filedata = File.open(values, 'rb') { |f| f.read }
1773
1794
  else
1774
1795
  basename = values[:filename]
1775
- filedata = values[:content] || File.open(values[:filename], 'rb') { |f| f.read }
1796
+ filedata = values
1776
1797
  end
1777
1798
  self.attachments[basename] = filedata
1778
1799
  end
@@ -1790,7 +1811,6 @@ module Mail
1790
1811
  # ready to send
1791
1812
  def ready_to_send!
1792
1813
  identify_and_set_transfer_encoding
1793
- parts.sort!([ "text/plain", "text/enriched", "text/html", "multipart/alternative" ])
1794
1814
  parts.each do |part|
1795
1815
  part.transport_encoding = transport_encoding
1796
1816
  part.ready_to_send!
@@ -1799,7 +1819,7 @@ module Mail
1799
1819
  end
1800
1820
 
1801
1821
  def encode!
1802
- 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.")
1803
1823
  ready_to_send!
1804
1824
  end
1805
1825
 
@@ -1815,16 +1835,13 @@ module Mail
1815
1835
  end
1816
1836
 
1817
1837
  def without_attachments!
1818
- return self unless has_attachments?
1819
-
1820
- parts.delete_if { |p| p.attachment? }
1821
- body_raw = if parts.empty?
1822
- ''
1823
- else
1824
- body.encoded
1825
- end
1838
+ if has_attachments?
1839
+ parts.delete_if { |p| p.attachment? }
1826
1840
 
1827
- @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
1828
1845
 
1829
1846
  self
1830
1847
  end
@@ -1857,7 +1874,7 @@ module Mail
1857
1874
  case
1858
1875
  when k == 'delivery_handler'
1859
1876
  begin
1860
- m.delivery_handler = Object.const_get(v) unless v.blank?
1877
+ m.delivery_handler = Object.const_get(v) unless Utilities.blank?(v)
1861
1878
  rescue NameError
1862
1879
  end
1863
1880
  when k == 'transport_encoding'
@@ -1967,7 +1984,7 @@ module Mail
1967
1984
 
1968
1985
  private
1969
1986
 
1970
- HEADER_SEPARATOR = /#{CRLF}#{CRLF}|#{CRLF}#{WSP}*#{CRLF}(?!#{WSP})/m
1987
+ HEADER_SEPARATOR = /#{CRLF}#{CRLF}/
1971
1988
 
1972
1989
  # 2.1. General Description
1973
1990
  # A message consists of header fields (collectively called "the header
@@ -1976,9 +1993,6 @@ module Mail
1976
1993
  # this standard. The body is simply a sequence of characters that
1977
1994
  # follows the header and is separated from the header by an empty line
1978
1995
  # (i.e., a line with nothing preceding the CRLF).
1979
- #
1980
- # Additionally, I allow for the case where someone might have put whitespace
1981
- # on the "gap line"
1982
1996
  def parse_message
1983
1997
  header_part, body_part = raw_source.lstrip.split(HEADER_SEPARATOR, 2)
1984
1998
  self.header = header_part
@@ -1987,7 +2001,7 @@ module Mail
1987
2001
 
1988
2002
  def raw_source=(value)
1989
2003
  value = value.dup.force_encoding(Encoding::BINARY) if RUBY_VERSION >= "1.9.1"
1990
- @raw_source = value.to_crlf
2004
+ @raw_source = ::Mail::Utilities.to_crlf(value)
1991
2005
  end
1992
2006
 
1993
2007
  # see comments to body=. We take data and process it lazily
@@ -1999,11 +2013,9 @@ module Mail
1999
2013
  @body_raw = nil
2000
2014
  add_encoding_to_body
2001
2015
  when @body && @body.multipart?
2002
- @body << Mail::Part.new(value)
2003
- add_encoding_to_body
2016
+ self.text_part = value
2004
2017
  else
2005
2018
  @body_raw = value
2006
- # process_body_raw
2007
2019
  end
2008
2020
  end
2009
2021
 
@@ -2018,9 +2030,9 @@ module Mail
2018
2030
 
2019
2031
  def set_envelope_header
2020
2032
  raw_string = raw_source.to_s
2021
- 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)
2022
2034
  set_envelope(match_data[1])
2023
- self.raw_source = raw_string.sub(match_data[0], "")
2035
+ self.raw_source = raw_string.sub(match_data[0], "")
2024
2036
  end
2025
2037
  end
2026
2038
 
@@ -2028,6 +2040,13 @@ module Mail
2028
2040
  body.split!(boundary)
2029
2041
  end
2030
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
+
2031
2050
  def add_encoding_to_body
2032
2051
  if has_content_transfer_encoding?
2033
2052
  @body.encoding = content_transfer_encoding
@@ -2035,18 +2054,18 @@ module Mail
2035
2054
  end
2036
2055
 
2037
2056
  def identify_and_set_transfer_encoding
2038
- if body && body.multipart?
2039
- self.content_transfer_encoding = @transport_encoding
2040
- else
2041
- self.content_transfer_encoding = body.get_best_encoding(@transport_encoding)
2042
- 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
2043
2062
  end
2044
2063
 
2045
2064
  def add_required_fields
2046
2065
  add_required_message_fields
2047
2066
  add_multipart_mixed_header if body.multipart?
2048
2067
  add_content_type unless has_content_type?
2049
- add_charset unless has_charset?
2068
+ add_charset if text? && !has_charset?
2050
2069
  add_content_transfer_encoding unless has_content_transfer_encoding?
2051
2070
  end
2052
2071
 
@@ -2122,10 +2141,10 @@ module Mail
2122
2141
  content_disp_name = header[:content_disposition].filename rescue nil
2123
2142
  content_loc_name = header[:content_location].location rescue nil
2124
2143
  case
2125
- when content_type && content_type_name
2126
- filename = content_type_name
2127
2144
  when content_disposition && content_disp_name
2128
2145
  filename = content_disp_name
2146
+ when content_type && content_type_name
2147
+ filename = content_type_name
2129
2148
  when content_location && content_loc_name
2130
2149
  filename = content_loc_name
2131
2150
  else
@@ -2146,20 +2165,7 @@ module Mail
2146
2165
  end
2147
2166
 
2148
2167
  def decode_body_as_text
2149
- body_text = decode_body
2150
- if charset
2151
- if RUBY_VERSION < '1.9'
2152
- require 'iconv'
2153
- return Iconv.conv("UTF-8//TRANSLIT//IGNORE", charset, body_text)
2154
- else
2155
- if encoding = Encoding.find(charset) rescue nil
2156
- body_text.force_encoding(encoding)
2157
- return body_text.encode(Encoding::UTF_8, :undef => :replace, :invalid => :replace, :replace => '')
2158
- end
2159
- end
2160
- end
2161
- body_text
2168
+ Encodings.transcode_charset decode_body, charset, 'UTF-8'
2162
2169
  end
2163
-
2164
2170
  end
2165
2171
  end