mail 2.4.4 → 2.6.3

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 (163) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +156 -0
  3. data/CONTRIBUTING.md +21 -6
  4. data/Dependencies.txt +0 -1
  5. data/Gemfile +10 -21
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +52 -32
  8. data/Rakefile +11 -22
  9. data/lib/mail/attachments_list.rb +2 -2
  10. data/lib/mail/body.rb +33 -9
  11. data/lib/mail/check_delivery_params.rb +20 -0
  12. data/lib/mail/configuration.rb +1 -1
  13. data/lib/mail/{patterns.rb → constants.rb} +26 -6
  14. data/lib/mail/core_extensions/nil.rb +4 -2
  15. data/lib/mail/core_extensions/object.rb +8 -8
  16. data/lib/mail/core_extensions/smtp.rb +12 -13
  17. data/lib/mail/core_extensions/string.rb +19 -6
  18. data/lib/mail/elements/address.rb +82 -141
  19. data/lib/mail/elements/address_list.rb +9 -42
  20. data/lib/mail/elements/content_disposition_element.rb +3 -7
  21. data/lib/mail/elements/content_location_element.rb +2 -6
  22. data/lib/mail/elements/content_transfer_encoding_element.rb +3 -10
  23. data/lib/mail/elements/content_type_element.rb +4 -8
  24. data/lib/mail/elements/date_time_element.rb +3 -7
  25. data/lib/mail/elements/envelope_from_element.rb +18 -13
  26. data/lib/mail/elements/message_ids_element.rb +1 -6
  27. data/lib/mail/elements/mime_version_element.rb +3 -7
  28. data/lib/mail/elements/phrase_list.rb +2 -7
  29. data/lib/mail/elements/received_element.rb +3 -7
  30. data/lib/mail/elements.rb +12 -12
  31. data/lib/mail/encodings/quoted_printable.rb +4 -3
  32. data/lib/mail/encodings/unix_to_unix.rb +17 -0
  33. data/lib/mail/encodings.rb +53 -38
  34. data/lib/mail/envelope.rb +0 -5
  35. data/lib/mail/field.rb +131 -118
  36. data/lib/mail/field_list.rb +18 -18
  37. data/lib/mail/fields/bcc_field.rb +2 -2
  38. data/lib/mail/fields/cc_field.rb +2 -2
  39. data/lib/mail/fields/comments_field.rb +1 -1
  40. data/lib/mail/fields/common/common_address.rb +32 -22
  41. data/lib/mail/fields/common/common_date.rb +0 -7
  42. data/lib/mail/fields/common/common_field.rb +10 -3
  43. data/lib/mail/fields/common/common_message_id.rb +9 -5
  44. data/lib/mail/fields/common/parameter_hash.rb +3 -3
  45. data/lib/mail/fields/content_disposition_field.rb +1 -0
  46. data/lib/mail/fields/content_id_field.rb +1 -2
  47. data/lib/mail/fields/content_transfer_encoding_field.rb +2 -8
  48. data/lib/mail/fields/content_type_field.rb +5 -2
  49. data/lib/mail/fields/date_field.rb +14 -14
  50. data/lib/mail/fields/from_field.rb +2 -2
  51. data/lib/mail/fields/in_reply_to_field.rb +2 -1
  52. data/lib/mail/fields/keywords_field.rb +1 -1
  53. data/lib/mail/fields/message_id_field.rb +2 -3
  54. data/lib/mail/fields/references_field.rb +2 -1
  55. data/lib/mail/fields/reply_to_field.rb +2 -2
  56. data/lib/mail/fields/resent_bcc_field.rb +2 -2
  57. data/lib/mail/fields/resent_cc_field.rb +2 -2
  58. data/lib/mail/fields/resent_from_field.rb +2 -2
  59. data/lib/mail/fields/resent_sender_field.rb +3 -3
  60. data/lib/mail/fields/resent_to_field.rb +2 -2
  61. data/lib/mail/fields/sender_field.rb +8 -8
  62. data/lib/mail/fields/to_field.rb +2 -2
  63. data/lib/mail/fields/unstructured_field.rb +44 -31
  64. data/lib/mail/fields.rb +32 -32
  65. data/lib/mail/header.rb +47 -37
  66. data/lib/mail/mail.rb +15 -1
  67. data/lib/mail/matchers/has_sent_mail.rb +36 -3
  68. data/lib/mail/message.rb +164 -57
  69. data/lib/mail/multibyte/chars.rb +4 -4
  70. data/lib/mail/multibyte/unicode.rb +9 -1
  71. data/lib/mail/network/delivery_methods/exim.rb +2 -3
  72. data/lib/mail/network/delivery_methods/file_delivery.rb +5 -0
  73. data/lib/mail/network/delivery_methods/sendmail.rb +35 -8
  74. data/lib/mail/network/delivery_methods/smtp.rb +34 -45
  75. data/lib/mail/network/delivery_methods/smtp_connection.rb +9 -22
  76. data/lib/mail/network/delivery_methods/test_mailer.rb +6 -2
  77. data/lib/mail/network/retriever_methods/imap.rb +32 -19
  78. data/lib/mail/network/retriever_methods/pop3.rb +2 -2
  79. data/lib/mail/network/retriever_methods/test_retriever.rb +11 -15
  80. data/lib/mail/network.rb +9 -9
  81. data/lib/mail/parsers/address_lists_parser.rb +132 -0
  82. data/lib/mail/parsers/content_disposition_parser.rb +67 -0
  83. data/lib/mail/parsers/content_location_parser.rb +35 -0
  84. data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
  85. data/lib/mail/parsers/content_type_parser.rb +66 -0
  86. data/lib/mail/parsers/date_time_parser.rb +36 -0
  87. data/lib/mail/parsers/envelope_from_parser.rb +45 -0
  88. data/lib/mail/parsers/message_ids_parser.rb +39 -0
  89. data/lib/mail/parsers/mime_version_parser.rb +41 -0
  90. data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
  91. data/lib/mail/parsers/ragel/common.rl +185 -0
  92. data/lib/mail/parsers/ragel/date_time.rl +30 -0
  93. data/lib/mail/parsers/ragel/parser_info.rb +61 -0
  94. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
  95. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
  96. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
  97. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
  98. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
  99. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
  100. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
  101. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
  102. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
  103. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
  104. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
  105. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
  106. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2149 -0
  107. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
  108. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
  109. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
  110. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
  111. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
  112. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
  113. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
  114. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
  115. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
  116. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
  117. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
  118. data/lib/mail/parsers/ragel/ruby.rb +40 -0
  119. data/lib/mail/parsers/ragel.rb +17 -0
  120. data/lib/mail/parsers/received_parser.rb +47 -0
  121. data/lib/mail/parsers.rb +26 -0
  122. data/lib/mail/part.rb +6 -2
  123. data/lib/mail/parts_list.rb +5 -3
  124. data/lib/mail/utilities.rb +70 -60
  125. data/lib/mail/values/unicode_tables.dat +0 -0
  126. data/lib/mail/version.rb +7 -15
  127. data/lib/mail/version_specific/ruby_1_8.rb +25 -4
  128. data/lib/mail/version_specific/ruby_1_9.rb +110 -30
  129. data/lib/mail.rb +20 -19
  130. metadata +129 -73
  131. data/Gemfile.lock +0 -36
  132. data/lib/VERSION +0 -4
  133. data/lib/mail/core_extensions/shell_escape.rb +0 -56
  134. data/lib/mail/parsers/address_lists.rb +0 -64
  135. data/lib/mail/parsers/address_lists.treetop +0 -19
  136. data/lib/mail/parsers/content_disposition.rb +0 -535
  137. data/lib/mail/parsers/content_disposition.treetop +0 -46
  138. data/lib/mail/parsers/content_location.rb +0 -139
  139. data/lib/mail/parsers/content_location.treetop +0 -20
  140. data/lib/mail/parsers/content_transfer_encoding.rb +0 -162
  141. data/lib/mail/parsers/content_transfer_encoding.treetop +0 -20
  142. data/lib/mail/parsers/content_type.rb +0 -967
  143. data/lib/mail/parsers/content_type.treetop +0 -68
  144. data/lib/mail/parsers/date_time.rb +0 -114
  145. data/lib/mail/parsers/date_time.treetop +0 -11
  146. data/lib/mail/parsers/envelope_from.rb +0 -194
  147. data/lib/mail/parsers/envelope_from.treetop +0 -32
  148. data/lib/mail/parsers/message_ids.rb +0 -45
  149. data/lib/mail/parsers/message_ids.treetop +0 -15
  150. data/lib/mail/parsers/mime_version.rb +0 -144
  151. data/lib/mail/parsers/mime_version.treetop +0 -19
  152. data/lib/mail/parsers/phrase_lists.rb +0 -45
  153. data/lib/mail/parsers/phrase_lists.treetop +0 -15
  154. data/lib/mail/parsers/received.rb +0 -71
  155. data/lib/mail/parsers/received.treetop +0 -11
  156. data/lib/mail/parsers/rfc2045.rb +0 -464
  157. data/lib/mail/parsers/rfc2045.treetop +0 -36
  158. data/lib/mail/parsers/rfc2822.rb +0 -5341
  159. data/lib/mail/parsers/rfc2822.treetop +0 -410
  160. data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
  161. data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
  162. data/lib/tasks/corpus.rake +0 -125
  163. data/lib/tasks/treetop.rake +0 -10
@@ -9,6 +9,7 @@ module Mail
9
9
 
10
10
  def initialize(value = nil, charset = 'utf-8')
11
11
  self.charset = charset
12
+ ensure_filename_quoted(value)
12
13
  super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
13
14
  self.parse
14
15
  self
@@ -55,8 +55,7 @@ module Mail
55
55
  private
56
56
 
57
57
  def generate_content_id
58
- fqdn = ::Socket.gethostname
59
- "<#{Mail.random_tag}@#{fqdn}.mail>"
58
+ "<#{Mail.random_tag}@#{::Socket.gethostname}.mail>"
60
59
  end
61
60
 
62
61
  end
@@ -10,8 +10,8 @@ module Mail
10
10
 
11
11
  def initialize(value = nil, charset = 'utf-8')
12
12
  self.charset = charset
13
- value = '7bit' if value.to_s =~ /7-bit/i
14
- value = '8bit' if value.to_s =~ /8-bit/i
13
+ value = '7bit' if value.to_s =~ /7-?bits?/i
14
+ value = '8bit' if value.to_s =~ /8-?bits?/i
15
15
  super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
16
16
  self.parse
17
17
  self
@@ -23,12 +23,6 @@ module Mail
23
23
  end
24
24
  end
25
25
 
26
- def tree
27
- STDERR.puts("tree is deprecated. Please use encoding to get parse result\n#{caller}")
28
- @element ||= Mail::ContentTransferEncodingElement.new(value)
29
- @tree ||= @element.tree
30
- end
31
-
32
26
  def element
33
27
  @element ||= Mail::ContentTransferEncodingElement.new(value)
34
28
  end
@@ -19,6 +19,7 @@ module Mail
19
19
  @parameters = nil
20
20
  value = strip_field(FIELD_NAME, value)
21
21
  end
22
+ ensure_filename_quoted(value)
22
23
  super(CAPITALIZED_FIELD, value, charset)
23
24
  self.parse
24
25
  self
@@ -141,7 +142,9 @@ module Mail
141
142
  def sanatize( val )
142
143
 
143
144
  # TODO: check if there are cases where whitespace is not a separator
144
- val = val.tr(' ',';').
145
+ val = val.
146
+ gsub(/\s*=\s*/,'='). # remove whitespaces around equal sign
147
+ tr(' ',';').
145
148
  squeeze(';').
146
149
  gsub(';', '; '). #use '; ' as a separator (or EOL)
147
150
  gsub(/;\s*$/,'') #remove trailing to keep examples below
@@ -177,7 +180,7 @@ module Mail
177
180
  params = $2.to_s.split(/\s+/)
178
181
  params = params.map { |i| i.to_s.chomp.strip }
179
182
  params = params.map { |i| i.split(/\s*\=\s*/) }
180
- params = params.map { |i| "#{i[0]}=#{dquote(i[1].to_s)}" }.join('; ')
183
+ params = params.map { |i| "#{i[0]}=#{dquote(i[1].to_s.gsub(/;$/,""))}" }.join('; ')
181
184
  "#{type}; #{params}"
182
185
  when val =~ /^\s*$/
183
186
  'text/plain'
@@ -1,18 +1,18 @@
1
1
  # encoding: utf-8
2
- #
2
+ #
3
3
  # = Date Field
4
- #
4
+ #
5
5
  # The Date field inherits from StructuredField and handles the Date: header
6
6
  # field in the email.
7
- #
7
+ #
8
8
  # Sending date to a mail message will instantiate a Mail::Field object that
9
- # has a DateField as it's field type. This includes all Mail::CommonAddress
9
+ # has a DateField as its field type. This includes all Mail::CommonAddress
10
10
  # module instance methods.
11
- #
11
+ #
12
12
  # There must be excatly one Date field in an RFC2822 email.
13
- #
13
+ #
14
14
  # == Examples:
15
- #
15
+ #
16
16
  # mail = Mail.new
17
17
  # mail.date = 'Mon, 24 Nov 1997 14:22:01 -0800'
18
18
  # mail.date #=> #<DateTime: 211747170121/86400,-1/3,2299161>
@@ -20,17 +20,17 @@
20
20
  # mail[:date] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::DateField:0x180e1c4
21
21
  # mail['date'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::DateField:0x180e1c4
22
22
  # mail['Date'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::DateField:0x180e1c4
23
- #
23
+ #
24
24
  require 'mail/fields/common/common_date'
25
25
 
26
26
  module Mail
27
27
  class DateField < StructuredField
28
-
28
+
29
29
  include Mail::CommonDate
30
-
30
+
31
31
  FIELD_NAME = 'date'
32
32
  CAPITALIZED_FIELD = "Date"
33
-
33
+
34
34
  def initialize(value = nil, charset = 'utf-8')
35
35
  self.charset = charset
36
36
  if value.blank?
@@ -44,14 +44,14 @@ module Mail
44
44
  rescue ArgumentError => e
45
45
  raise e unless "invalid date"==e.message
46
46
  end
47
-
47
+
48
48
  def encoded
49
49
  do_encode(CAPITALIZED_FIELD)
50
50
  end
51
-
51
+
52
52
  def decoded
53
53
  do_decode
54
54
  end
55
-
55
+
56
56
  end
57
57
  end
@@ -6,7 +6,7 @@
6
6
  # field in the email.
7
7
  #
8
8
  # Sending from to a mail message will instantiate a Mail::Field object that
9
- # has a FromField as it's field type. This includes all Mail::CommonAddress
9
+ # has a FromField as its field type. This includes all Mail::CommonAddress
10
10
  # module instance metods.
11
11
  #
12
12
  # Only one From field can appear in a header, though it can have multiple
@@ -16,7 +16,7 @@
16
16
  #
17
17
  # mail = Mail.new
18
18
  # mail.from = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
- # mail.from #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
19
+ # mail.from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
20
20
  # mail[:from] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::FromField:0x180e1c4
21
21
  # mail['from'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::FromField:0x180e1c4
22
22
  # mail['From'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::FromField:0x180e1c4
@@ -6,7 +6,7 @@
6
6
  # In-Reply-To: header field in the email.
7
7
  #
8
8
  # Sending in_reply_to to a mail message will instantiate a Mail::Field object that
9
- # has a InReplyToField as it's field type. This includes all Mail::CommonMessageId
9
+ # has a InReplyToField as its field type. This includes all Mail::CommonMessageId
10
10
  # module instance metods.
11
11
  #
12
12
  # Note that, the #message_ids method will return an array of message IDs without the
@@ -38,6 +38,7 @@ module Mail
38
38
 
39
39
  def initialize(value = nil, charset = 'utf-8')
40
40
  self.charset = charset
41
+ value = value.join("\r\n\s") if value.is_a?(Array)
41
42
  super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
42
43
  self.parse
43
44
  self
@@ -29,7 +29,7 @@ module Mail
29
29
  end
30
30
 
31
31
  def encoded
32
- "#{CAPITALIZED_FIELD}: #{keywords.join(', ')}\r\n"
32
+ "#{CAPITALIZED_FIELD}: #{keywords.join(",\r\n ")}\r\n"
33
33
  end
34
34
 
35
35
  def decoded
@@ -6,7 +6,7 @@
6
6
  # Message-ID: header field in the email.
7
7
  #
8
8
  # Sending message_id to a mail message will instantiate a Mail::Field object that
9
- # has a MessageIdField as it's field type. This includes all Mail::CommonMessageId
9
+ # has a MessageIdField as its field type. This includes all Mail::CommonMessageId
10
10
  # module instance metods.
11
11
  #
12
12
  # Only one MessageId field can appear in a header, and syntactically it can only have
@@ -75,8 +75,7 @@ module Mail
75
75
  private
76
76
 
77
77
  def generate_message_id
78
- fqdn = ::Socket.gethostname
79
- "<#{Mail.random_tag}@#{fqdn}.mail>"
78
+ "<#{Mail.random_tag}@#{::Socket.gethostname}.mail>"
80
79
  end
81
80
 
82
81
  end
@@ -6,7 +6,7 @@
6
6
  # field in the email.
7
7
  #
8
8
  # Sending references to a mail message will instantiate a Mail::Field object that
9
- # has a ReferencesField as it's field type. This includes all Mail::CommonAddress
9
+ # has a ReferencesField as its field type. This includes all Mail::CommonAddress
10
10
  # module instance metods.
11
11
  #
12
12
  # Note that, the #message_ids method will return an array of message IDs without the
@@ -38,6 +38,7 @@ module Mail
38
38
 
39
39
  def initialize(value = nil, charset = 'utf-8')
40
40
  self.charset = charset
41
+ value = value.join("\r\n\s") if value.is_a?(Array)
41
42
  super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
42
43
  self.parse
43
44
  self
@@ -6,7 +6,7 @@
6
6
  # field in the email.
7
7
  #
8
8
  # Sending reply_to to a mail message will instantiate a Mail::Field object that
9
- # has a ReplyToField as it's field type. This includes all Mail::CommonAddress
9
+ # has a ReplyToField as its field type. This includes all Mail::CommonAddress
10
10
  # module instance metods.
11
11
  #
12
12
  # Only one Reply-To field can appear in a header, though it can have multiple
@@ -16,7 +16,7 @@
16
16
  #
17
17
  # mail = Mail.new
18
18
  # mail.reply_to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
- # mail.reply_to #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
19
+ # mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
20
20
  # mail[:reply_to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ReplyToField:0x180e1c4
21
21
  # mail['reply-to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ReplyToField:0x180e1c4
22
22
  # mail['Reply-To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ReplyToField:0x180e1c4
@@ -6,7 +6,7 @@
6
6
  # Resent-Bcc: header field in the email.
7
7
  #
8
8
  # Sending resent_bcc to a mail message will instantiate a Mail::Field object that
9
- # has a ResentBccField as it's field type. This includes all Mail::CommonAddress
9
+ # has a ResentBccField as its field type. This includes all Mail::CommonAddress
10
10
  # module instance metods.
11
11
  #
12
12
  # Only one Resent-Bcc field can appear in a header, though it can have multiple
@@ -16,7 +16,7 @@
16
16
  #
17
17
  # mail = Mail.new
18
18
  # mail.resent_bcc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
- # mail.resent_bcc #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
19
+ # mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
20
20
  # mail[:resent_bcc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentBccField:0x180e1c4
21
21
  # mail['resent-bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentBccField:0x180e1c4
22
22
  # mail['Resent-Bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentBccField:0x180e1c4
@@ -6,7 +6,7 @@
6
6
  # field in the email.
7
7
  #
8
8
  # Sending resent_cc to a mail message will instantiate a Mail::Field object that
9
- # has a ResentCcField as it's field type. This includes all Mail::CommonAddress
9
+ # has a ResentCcField as its field type. This includes all Mail::CommonAddress
10
10
  # module instance metods.
11
11
  #
12
12
  # Only one Resent-Cc field can appear in a header, though it can have multiple
@@ -16,7 +16,7 @@
16
16
  #
17
17
  # mail = Mail.new
18
18
  # mail.resent_cc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
- # mail.resent_cc #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
19
+ # mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
20
20
  # mail[:resent_cc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentCcField:0x180e1c4
21
21
  # mail['resent-cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentCcField:0x180e1c4
22
22
  # mail['Resent-Cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentCcField:0x180e1c4
@@ -6,7 +6,7 @@
6
6
  # field in the email.
7
7
  #
8
8
  # Sending resent_from to a mail message will instantiate a Mail::Field object that
9
- # has a ResentFromField as it's field type. This includes all Mail::CommonAddress
9
+ # has a ResentFromField as its field type. This includes all Mail::CommonAddress
10
10
  # module instance metods.
11
11
  #
12
12
  # Only one Resent-From field can appear in a header, though it can have multiple
@@ -16,7 +16,7 @@
16
16
  #
17
17
  # mail = Mail.new
18
18
  # mail.resent_from = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
- # mail.resent_from #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
19
+ # mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
20
20
  # mail[:resent_from] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentFromField:0x180e1c4
21
21
  # mail['resent-from'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentFromField:0x180e1c4
22
22
  # mail['Resent-From'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentFromField:0x180e1c4
@@ -6,7 +6,7 @@
6
6
  # field in the email.
7
7
  #
8
8
  # Sending resent_sender to a mail message will instantiate a Mail::Field object that
9
- # has a ResentSenderField as it's field type. This includes all Mail::CommonAddress
9
+ # has a ResentSenderField as its field type. This includes all Mail::CommonAddress
10
10
  # module instance metods.
11
11
  #
12
12
  # Only one Resent-Sender field can appear in a header, though it can have multiple
@@ -16,7 +16,7 @@
16
16
  #
17
17
  # mail = Mail.new
18
18
  # mail.resent_sender = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
- # mail.resent_sender #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentSenderField:0x180e1c4
19
+ # mail.resent_sender #=> ['mikel@test.lindsaar.net']
20
20
  # mail[:resent_sender] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentSenderField:0x180e1c4
21
21
  # mail['resent-sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentSenderField:0x180e1c4
22
22
  # mail['Resent-Sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentSenderField:0x180e1c4
@@ -47,7 +47,7 @@ module Mail
47
47
  end
48
48
 
49
49
  def address
50
- tree.addresses.first
50
+ address_list.addresses.first
51
51
  end
52
52
 
53
53
  def encoded
@@ -6,7 +6,7 @@
6
6
  # field in the email.
7
7
  #
8
8
  # Sending resent_to to a mail message will instantiate a Mail::Field object that
9
- # has a ResentToField as it's field type. This includes all Mail::CommonAddress
9
+ # has a ResentToField as its field type. This includes all Mail::CommonAddress
10
10
  # module instance metods.
11
11
  #
12
12
  # Only one Resent-To field can appear in a header, though it can have multiple
@@ -16,7 +16,7 @@
16
16
  #
17
17
  # mail = Mail.new
18
18
  # mail.resent_to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
- # mail.resent_to #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
19
+ # mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
20
20
  # mail[:resent_to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentToField:0x180e1c4
21
21
  # mail['resent-to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentToField:0x180e1c4
22
22
  # mail['Resent-To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentToField:0x180e1c4
@@ -6,7 +6,7 @@
6
6
  # field in the email.
7
7
  #
8
8
  # Sending sender to a mail message will instantiate a Mail::Field object that
9
- # has a SenderField as it's field type. This includes all Mail::CommonAddress
9
+ # has a SenderField as its field type. This includes all Mail::CommonAddress
10
10
  # module instance metods.
11
11
  #
12
12
  # Only one Sender field can appear in a header, though it can have multiple
@@ -15,16 +15,16 @@
15
15
  # == Examples:
16
16
  #
17
17
  # mail = Mail.new
18
- # mail.sender = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
- # mail.sender #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
18
+ # mail.sender = 'Mikel Lindsaar <mikel@test.lindsaar.net>'
19
+ # mail.sender #=> 'mikel@test.lindsaar.net'
20
20
  # mail[:sender] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
21
21
  # mail['sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
22
22
  # mail['Sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
23
23
  #
24
- # mail[:sender].encoded #=> 'Sender: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
25
- # mail[:sender].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
26
- # mail[:sender].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
27
- # mail[:sender].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
24
+ # mail[:sender].encoded #=> "Sender: Mikel Lindsaar <mikel@test.lindsaar.net>\r\n"
25
+ # mail[:sender].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>'
26
+ # mail[:sender].addresses #=> ['mikel@test.lindsaar.net']
27
+ # mail[:sender].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>']
28
28
  #
29
29
  require 'mail/fields/common/common_address'
30
30
 
@@ -48,7 +48,7 @@ module Mail
48
48
  end
49
49
 
50
50
  def address
51
- tree.addresses.first
51
+ address_list.addresses.first
52
52
  end
53
53
 
54
54
  def encoded
@@ -6,7 +6,7 @@
6
6
  # field in the email.
7
7
  #
8
8
  # Sending to to a mail message will instantiate a Mail::Field object that
9
- # has a ToField as it's field type. This includes all Mail::CommonAddress
9
+ # has a ToField as its field type. This includes all Mail::CommonAddress
10
10
  # module instance metods.
11
11
  #
12
12
  # Only one To field can appear in a header, though it can have multiple
@@ -16,7 +16,7 @@
16
16
  #
17
17
  # mail = Mail.new
18
18
  # mail.to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
- # mail.to #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
19
+ # mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
20
20
  # mail[:to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
21
21
  # mail['to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
22
22
  # mail['To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
@@ -6,7 +6,7 @@ module Mail
6
6
  #
7
7
  # ===Per RFC 2822:
8
8
  # 2.2.1. Unstructured Header Field Bodies
9
- #
9
+ #
10
10
  # Some field bodies in this standard are defined simply as
11
11
  # "unstructured" (which is specified below as any US-ASCII characters,
12
12
  # except for CR and LF) with no further restrictions. These are
@@ -15,20 +15,29 @@ module Mail
15
15
  # with no further processing (except for header "folding" and
16
16
  # "unfolding" as described in section 2.2.3).
17
17
  class UnstructuredField
18
-
18
+
19
19
  include Mail::CommonField
20
20
  include Mail::Utilities
21
-
21
+
22
22
  attr_accessor :charset
23
23
  attr_reader :errors
24
-
24
+
25
25
  def initialize(name, value, charset = nil)
26
26
  @errors = []
27
+
28
+ if value.is_a?(Array)
29
+ # Probably has arrived here from a failed parse of an AddressList Field
30
+ value = value.join(', ')
31
+ else
32
+ # Ensure we are dealing with a string
33
+ value = value.to_s
34
+ end
35
+
27
36
  if charset
28
37
  self.charset = charset
29
38
  else
30
- if value.to_s.respond_to?(:encoding)
31
- self.charset = value.to_s.encoding
39
+ if value.respond_to?(:encoding)
40
+ self.charset = value.encoding
32
41
  else
33
42
  self.charset = $KCODE
34
43
  end
@@ -37,11 +46,11 @@ module Mail
37
46
  self.value = value
38
47
  self
39
48
  end
40
-
49
+
41
50
  def encoded
42
51
  do_encode
43
52
  end
44
-
53
+
45
54
  def decoded
46
55
  do_decode
47
56
  end
@@ -49,25 +58,23 @@ module Mail
49
58
  def default
50
59
  decoded
51
60
  end
52
-
61
+
53
62
  def parse # An unstructured field does not parse
54
63
  self
55
64
  end
56
65
 
57
66
  private
58
-
67
+
59
68
  def do_encode
60
69
  value.nil? ? '' : "#{wrapped_value}\r\n"
61
70
  end
62
-
71
+
63
72
  def do_decode
64
- result = value.blank? ? nil : Encodings.decode_encode(value, :decode)
65
- result.encode!(value.encoding || "UTF-8") if RUBY_VERSION >= '1.9' && !result.blank?
66
- result
73
+ value.blank? ? nil : Encodings.decode_encode(value, :decode)
67
74
  end
68
-
75
+
69
76
  # 2.2.3. Long Header Fields
70
- #
77
+ #
71
78
  # Each header field is logically a single line of characters comprising
72
79
  # the field name, the colon, and the field body. For convenience
73
80
  # however, and to deal with the 998/78 character limitations per line,
@@ -76,14 +83,14 @@ module Mail
76
83
  # that wherever this standard allows for folding white space (not
77
84
  # simply WSP characters), a CRLF may be inserted before any WSP. For
78
85
  # example, the header field:
79
- #
86
+ #
80
87
  # Subject: This is a test
81
- #
88
+ #
82
89
  # can be represented as:
83
- #
90
+ #
84
91
  # Subject: This
85
92
  # is a test
86
- #
93
+ #
87
94
  # Note: Though structured field bodies are defined in such a way that
88
95
  # folding can take place between many of the lexical tokens (and even
89
96
  # within some of the lexical tokens), folding SHOULD be limited to
@@ -95,9 +102,9 @@ module Mail
95
102
  def wrapped_value # :nodoc:
96
103
  wrap_lines(name, fold("#{name}: ".length))
97
104
  end
98
-
105
+
99
106
  # 6.2. Display of 'encoded-word's
100
- #
107
+ #
101
108
  # When displaying a particular header field that contains multiple
102
109
  # 'encoded-word's, any 'linear-white-space' that separates a pair of
103
110
  # adjacent 'encoded-word's is ignored. (This is to allow the use of
@@ -131,29 +138,35 @@ module Mail
131
138
  else
132
139
  words = decoded_string.split(/[ \t]/)
133
140
  end
134
-
141
+
135
142
  folded_lines = []
136
143
  while !words.empty?
137
144
  limit = 78 - prepend
138
145
  limit = limit - 7 - encoding.length if should_encode
139
146
  line = ""
147
+ first_word = true
140
148
  while !words.empty?
141
149
  break unless word = words.first.dup
142
- word.encode!(charset) if defined?(Encoding) && charset
150
+ word.encode!(charset) if charset && word.respond_to?(:encode!)
143
151
  word = encode(word) if should_encode
144
152
  word = encode_crlf(word)
145
153
  # Skip to next line if we're going to go past the limit
146
154
  # Unless this is the first word, in which case we're going to add it anyway
147
155
  # Note: This means that a word that's longer than 998 characters is going to break the spec. Please fix if this is a problem for you.
148
- # (The fix, it seems, would be to use encoded-word encoding on it, because that way you can break it across multiple lines and
156
+ # (The fix, it seems, would be to use encoded-word encoding on it, because that way you can break it across multiple lines and
149
157
  # the linebreak will be ignored)
150
158
  break if !line.empty? && (line.length + word.length + 1 > limit)
151
159
  # Remove the word from the queue ...
152
160
  words.shift
153
161
  # Add word separator
154
- line << " " unless (line.empty? || should_encode)
162
+ if first_word
163
+ first_word = false
164
+ else
165
+ line << " " if !should_encode
166
+ end
167
+
155
168
  # ... add it in encoded form to the current line
156
- line << word
169
+ line << word
157
170
  end
158
171
  # Encode the line if necessary
159
172
  line = "=?#{encoding}?Q?#{line}?=" if should_encode
@@ -163,9 +176,9 @@ module Mail
163
176
  end
164
177
  folded_lines
165
178
  end
166
-
179
+
167
180
  def encode(value)
168
- value = [value].pack("M").gsub("=\n", '')
181
+ value = [value].pack(CAPITAL_M).gsub(EQUAL_LF, EMPTY)
169
182
  value.gsub!(/"/, '=22')
170
183
  value.gsub!(/\(/, '=28')
171
184
  value.gsub!(/\)/, '=29')
@@ -176,8 +189,8 @@ module Mail
176
189
  end
177
190
 
178
191
  def encode_crlf(value)
179
- value.gsub!("\r", '=0D')
180
- value.gsub!("\n", '=0A')
192
+ value.gsub!(CR, CR_ENCODED)
193
+ value.gsub!(LF, LF_ENCODED)
181
194
  value
182
195
  end
183
196
 
data/lib/mail/fields.rb CHANGED
@@ -1,35 +1,35 @@
1
1
  module Mail
2
- autoload :UnstructuredField, 'mail/fields/unstructured_field'
3
- autoload :StructuredField, 'mail/fields/structured_field'
4
- autoload :OptionalField, 'mail/fields/optional_field'
2
+ register_autoload :UnstructuredField, 'mail/fields/unstructured_field'
3
+ register_autoload :StructuredField, 'mail/fields/structured_field'
4
+ register_autoload :OptionalField, 'mail/fields/optional_field'
5
5
 
6
- autoload :BccField, 'mail/fields/bcc_field'
7
- autoload :CcField, 'mail/fields/cc_field'
8
- autoload :CommentsField, 'mail/fields/comments_field'
9
- autoload :ContentDescriptionField, 'mail/fields/content_description_field'
10
- autoload :ContentDispositionField, 'mail/fields/content_disposition_field'
11
- autoload :ContentIdField, 'mail/fields/content_id_field'
12
- autoload :ContentLocationField, 'mail/fields/content_location_field'
13
- autoload :ContentTransferEncodingField, 'mail/fields/content_transfer_encoding_field'
14
- autoload :ContentTypeField, 'mail/fields/content_type_field'
15
- autoload :DateField, 'mail/fields/date_field'
16
- autoload :FromField, 'mail/fields/from_field'
17
- autoload :InReplyToField, 'mail/fields/in_reply_to_field'
18
- autoload :KeywordsField, 'mail/fields/keywords_field'
19
- autoload :MessageIdField, 'mail/fields/message_id_field'
20
- autoload :MimeVersionField, 'mail/fields/mime_version_field'
21
- autoload :ReceivedField, 'mail/fields/received_field'
22
- autoload :ReferencesField, 'mail/fields/references_field'
23
- autoload :ReplyToField, 'mail/fields/reply_to_field'
24
- autoload :ResentBccField, 'mail/fields/resent_bcc_field'
25
- autoload :ResentCcField, 'mail/fields/resent_cc_field'
26
- autoload :ResentDateField, 'mail/fields/resent_date_field'
27
- autoload :ResentFromField, 'mail/fields/resent_from_field'
28
- autoload :ResentMessageIdField, 'mail/fields/resent_message_id_field'
29
- autoload :ResentSenderField, 'mail/fields/resent_sender_field'
30
- autoload :ResentToField, 'mail/fields/resent_to_field'
31
- autoload :ReturnPathField, 'mail/fields/return_path_field'
32
- autoload :SenderField, 'mail/fields/sender_field'
33
- autoload :SubjectField, 'mail/fields/subject_field'
34
- autoload :ToField, 'mail/fields/to_field'
6
+ register_autoload :BccField, 'mail/fields/bcc_field'
7
+ register_autoload :CcField, 'mail/fields/cc_field'
8
+ register_autoload :CommentsField, 'mail/fields/comments_field'
9
+ register_autoload :ContentDescriptionField, 'mail/fields/content_description_field'
10
+ register_autoload :ContentDispositionField, 'mail/fields/content_disposition_field'
11
+ register_autoload :ContentIdField, 'mail/fields/content_id_field'
12
+ register_autoload :ContentLocationField, 'mail/fields/content_location_field'
13
+ register_autoload :ContentTransferEncodingField, 'mail/fields/content_transfer_encoding_field'
14
+ register_autoload :ContentTypeField, 'mail/fields/content_type_field'
15
+ register_autoload :DateField, 'mail/fields/date_field'
16
+ register_autoload :FromField, 'mail/fields/from_field'
17
+ register_autoload :InReplyToField, 'mail/fields/in_reply_to_field'
18
+ register_autoload :KeywordsField, 'mail/fields/keywords_field'
19
+ register_autoload :MessageIdField, 'mail/fields/message_id_field'
20
+ register_autoload :MimeVersionField, 'mail/fields/mime_version_field'
21
+ register_autoload :ReceivedField, 'mail/fields/received_field'
22
+ register_autoload :ReferencesField, 'mail/fields/references_field'
23
+ register_autoload :ReplyToField, 'mail/fields/reply_to_field'
24
+ register_autoload :ResentBccField, 'mail/fields/resent_bcc_field'
25
+ register_autoload :ResentCcField, 'mail/fields/resent_cc_field'
26
+ register_autoload :ResentDateField, 'mail/fields/resent_date_field'
27
+ register_autoload :ResentFromField, 'mail/fields/resent_from_field'
28
+ register_autoload :ResentMessageIdField, 'mail/fields/resent_message_id_field'
29
+ register_autoload :ResentSenderField, 'mail/fields/resent_sender_field'
30
+ register_autoload :ResentToField, 'mail/fields/resent_to_field'
31
+ register_autoload :ReturnPathField, 'mail/fields/return_path_field'
32
+ register_autoload :SenderField, 'mail/fields/sender_field'
33
+ register_autoload :SubjectField, 'mail/fields/subject_field'
34
+ register_autoload :ToField, 'mail/fields/to_field'
35
35
  end