mail 2.7.1 → 2.8.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +45 -28
  3. data/lib/mail/attachments_list.rb +2 -5
  4. data/lib/mail/body.rb +24 -47
  5. data/lib/mail/constants.rb +27 -5
  6. data/lib/mail/elements/address.rb +27 -27
  7. data/lib/mail/elements/address_list.rb +1 -1
  8. data/lib/mail/elements/content_disposition_element.rb +1 -1
  9. data/lib/mail/elements/content_location_element.rb +1 -1
  10. data/lib/mail/elements/content_transfer_encoding_element.rb +1 -1
  11. data/lib/mail/elements/content_type_element.rb +8 -4
  12. data/lib/mail/elements/date_time_element.rb +1 -1
  13. data/lib/mail/elements/envelope_from_element.rb +13 -7
  14. data/lib/mail/elements/message_ids_element.rb +14 -5
  15. data/lib/mail/elements/mime_version_element.rb +1 -1
  16. data/lib/mail/elements/phrase_list.rb +7 -2
  17. data/lib/mail/elements/received_element.rb +20 -6
  18. data/lib/mail/encodings/7bit.rb +5 -0
  19. data/lib/mail/encodings/base64.rb +2 -2
  20. data/lib/mail/encodings/quoted_printable.rb +2 -2
  21. data/lib/mail/encodings.rb +30 -59
  22. data/lib/mail/envelope.rb +11 -14
  23. data/lib/mail/field.rb +37 -53
  24. data/lib/mail/field_list.rb +60 -7
  25. data/lib/mail/fields/bcc_field.rb +34 -52
  26. data/lib/mail/fields/cc_field.rb +28 -49
  27. data/lib/mail/fields/comments_field.rb +27 -37
  28. data/lib/mail/fields/common_address_field.rb +170 -0
  29. data/lib/mail/fields/common_date_field.rb +58 -0
  30. data/lib/mail/fields/common_field.rb +77 -0
  31. data/lib/mail/fields/common_message_id_field.rb +42 -0
  32. data/lib/mail/fields/content_description_field.rb +7 -14
  33. data/lib/mail/fields/content_disposition_field.rb +13 -38
  34. data/lib/mail/fields/content_id_field.rb +24 -51
  35. data/lib/mail/fields/content_location_field.rb +11 -25
  36. data/lib/mail/fields/content_transfer_encoding_field.rb +31 -31
  37. data/lib/mail/fields/content_type_field.rb +46 -71
  38. data/lib/mail/fields/date_field.rb +23 -51
  39. data/lib/mail/fields/from_field.rb +28 -49
  40. data/lib/mail/fields/in_reply_to_field.rb +38 -49
  41. data/lib/mail/fields/keywords_field.rb +18 -31
  42. data/lib/mail/fields/message_id_field.rb +25 -71
  43. data/lib/mail/fields/mime_version_field.rb +19 -30
  44. data/lib/mail/fields/named_structured_field.rb +11 -0
  45. data/lib/mail/fields/named_unstructured_field.rb +11 -0
  46. data/lib/mail/fields/optional_field.rb +5 -6
  47. data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +12 -10
  48. data/lib/mail/fields/received_field.rb +43 -57
  49. data/lib/mail/fields/references_field.rb +35 -49
  50. data/lib/mail/fields/reply_to_field.rb +28 -49
  51. data/lib/mail/fields/resent_bcc_field.rb +28 -49
  52. data/lib/mail/fields/resent_cc_field.rb +28 -49
  53. data/lib/mail/fields/resent_date_field.rb +5 -29
  54. data/lib/mail/fields/resent_from_field.rb +28 -49
  55. data/lib/mail/fields/resent_message_id_field.rb +5 -29
  56. data/lib/mail/fields/resent_sender_field.rb +27 -56
  57. data/lib/mail/fields/resent_to_field.rb +28 -49
  58. data/lib/mail/fields/return_path_field.rb +50 -54
  59. data/lib/mail/fields/sender_field.rb +34 -55
  60. data/lib/mail/fields/structured_field.rb +3 -30
  61. data/lib/mail/fields/subject_field.rb +9 -11
  62. data/lib/mail/fields/to_field.rb +28 -49
  63. data/lib/mail/fields/unstructured_field.rb +16 -48
  64. data/lib/mail/header.rb +69 -110
  65. data/lib/mail/matchers/attachment_matchers.rb +15 -0
  66. data/lib/mail/message.rb +46 -64
  67. data/lib/mail/multibyte/chars.rb +8 -166
  68. data/lib/mail/multibyte/utils.rb +26 -43
  69. data/lib/mail/multibyte.rb +1 -11
  70. data/lib/mail/network/delivery_methods/exim.rb +5 -4
  71. data/lib/mail/network/delivery_methods/file_delivery.rb +11 -10
  72. data/lib/mail/network/delivery_methods/logger_delivery.rb +2 -5
  73. data/lib/mail/network/delivery_methods/sendmail.rb +27 -35
  74. data/lib/mail/network/delivery_methods/smtp.rb +3 -3
  75. data/lib/mail/network/delivery_methods/smtp_connection.rb +3 -12
  76. data/lib/mail/network/delivery_methods/test_mailer.rb +4 -2
  77. data/lib/mail/network/retriever_methods/base.rb +8 -8
  78. data/lib/mail/network/retriever_methods/imap.rb +2 -2
  79. data/lib/mail/network/retriever_methods/pop3.rb +2 -2
  80. data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
  81. data/lib/mail/parsers/address_lists_parser.rb +33070 -33064
  82. data/lib/mail/parsers/address_lists_parser.rl +7 -0
  83. data/lib/mail/parsers/content_disposition_parser.rb +833 -827
  84. data/lib/mail/parsers/content_disposition_parser.rl +7 -0
  85. data/lib/mail/parsers/content_location_parser.rb +770 -764
  86. data/lib/mail/parsers/content_location_parser.rl +7 -0
  87. data/lib/mail/parsers/content_transfer_encoding_parser.rb +474 -468
  88. data/lib/mail/parsers/content_transfer_encoding_parser.rl +7 -0
  89. data/lib/mail/parsers/content_type_parser.rb +971 -965
  90. data/lib/mail/parsers/content_type_parser.rl +7 -0
  91. data/lib/mail/parsers/date_time_parser.rb +838 -832
  92. data/lib/mail/parsers/date_time_parser.rl +7 -0
  93. data/lib/mail/parsers/envelope_from_parser.rb +3623 -3529
  94. data/lib/mail/parsers/envelope_from_parser.rl +7 -0
  95. data/lib/mail/parsers/message_ids_parser.rb +5107 -2800
  96. data/lib/mail/parsers/message_ids_parser.rl +12 -1
  97. data/lib/mail/parsers/mime_version_parser.rb +463 -457
  98. data/lib/mail/parsers/mime_version_parser.rl +7 -0
  99. data/lib/mail/parsers/phrase_lists_parser.rb +836 -830
  100. data/lib/mail/parsers/phrase_lists_parser.rl +8 -1
  101. data/lib/mail/parsers/received_parser.rb +8688 -8682
  102. data/lib/mail/parsers/received_parser.rl +7 -0
  103. data/lib/mail/parsers/rfc5322.rl +28 -13
  104. data/lib/mail/parsers.rb +11 -17
  105. data/lib/mail/part.rb +5 -9
  106. data/lib/mail/parts_list.rb +57 -0
  107. data/lib/mail/smtp_envelope.rb +57 -0
  108. data/lib/mail/utilities.rb +307 -69
  109. data/lib/mail/version.rb +3 -3
  110. data/lib/mail/yaml.rb +30 -0
  111. data/lib/mail.rb +0 -20
  112. metadata +74 -21
  113. data/lib/mail/check_delivery_params.rb +0 -60
  114. data/lib/mail/core_extensions/smtp.rb +0 -28
  115. data/lib/mail/core_extensions/string.rb +0 -17
  116. data/lib/mail/fields/common/address_container.rb +0 -17
  117. data/lib/mail/fields/common/common_address.rb +0 -161
  118. data/lib/mail/fields/common/common_date.rb +0 -36
  119. data/lib/mail/fields/common/common_field.rb +0 -52
  120. data/lib/mail/fields/common/common_message_id.rb +0 -49
  121. data/lib/mail/version_specific/ruby_1_8.rb +0 -163
  122. data/lib/mail/version_specific/ruby_1_9.rb +0 -278
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e806bc9b7c6c6df8de9c9dc80b4cf3a099bad3153f568d0ee4d9287cd34a014
4
- data.tar.gz: 182ed03957858cce70691eb79543f13d53e4ddf43684bf50bc011e904d3a84ae
3
+ metadata.gz: 6ed25dc984368dd9a0032804a298eb6120e860357a70e7afc170108c700d430e
4
+ data.tar.gz: 886556ae37645a3074ca43cf439388c4bcdd164cc4849de76df4cf19345f8893
5
5
  SHA512:
6
- metadata.gz: 3c42702e6529565ae63c486fef492b89a19eb394fb6fe5aaf004862257ef3d840579a3cabb95dd2075ddbc617e077110684d8f47052e51d0435b94ef4a2373c3
7
- data.tar.gz: 31278e7d48271cfec8541d1094fedd1cc62578a6d9f18e0eafd09ebcac4e5edf3e78a3b902aca3e97d7416d37b0f0c07ba2dde2f5462d6317058552bbc0dbfe7
6
+ metadata.gz: 545f9b3a4a2cb1e752bad67e09cc0f3587d352471db140a35c6b885a9e64e5998b65032ff0d61f731bd1c27ed9a70a46a84c62051c5e419d99e7bf9a14dadbce
7
+ data.tar.gz: 727057fbad623dc4eef62840a2b8a5cf65e6c8d469874d497de91e78c2df9ccdbde5090fdffb7b8843ca4e7416c04ca34ab8b544e848dbd62ec25751ac8649ed
data/README.md CHANGED
@@ -1,39 +1,35 @@
1
- # Mail [![Build Status](https://travis-ci.org/mikel/mail.png?branch=master)](https://travis-ci.org/mikel/mail)
1
+ # Mail [![Build Status](https://github.com/mikel/mail/actions/workflows/test.yml/badge.svg)](https://github.com/mikel/mail/actions/workflows/test.yml)
2
2
 
3
3
  ## Introduction
4
4
 
5
- Mail is an internet library for Ruby that is designed to handle emails
5
+ Mail is an internet library for Ruby that is designed to handle email
6
6
  generation, parsing and sending in a simple, rubyesque manner.
7
7
 
8
8
  The purpose of this library is to provide a single point of access to handle
9
- all email functions, including sending and receiving emails. All network
9
+ all email functions, including sending and receiving email. All network
10
10
  type actions are done through proxy methods to Net::SMTP, Net::POP3 etc.
11
11
 
12
12
  Built from my experience with TMail, it is designed to be a pure ruby
13
- implementation that makes generating, sending and parsing emails a no
13
+ implementation that makes generating, sending and parsing email a no
14
14
  brainer.
15
15
 
16
16
  It is also designed from the ground up to work with the more modern versions
17
- of Ruby. This is because Ruby > 1.9 handles text encodings much more wonderfully
18
- than Ruby 1.8.x and so these features have been taken full advantage of in this
19
- library allowing Mail to handle a lot more messages more cleanly than TMail.
20
- Mail does run on Ruby 1.8.x... it's just not as fun to code.
17
+ of Ruby. Modern Rubies handle text encodings much more wonderfully than before
18
+ so these features have been taken full advantage of in this library allowing
19
+ Mail to handle a lot more messages more cleanly than TMail.
21
20
 
22
21
  Finally, Mail has been designed with a very simple object oriented system
23
22
  that really opens up the email messages you are parsing, if you know what
24
23
  you are doing, you can fiddle with every last bit of your email directly.
25
24
 
26
- ## Donations
25
+ ## You can contribute to this library
27
26
 
28
- Mail has been downloaded millions of times, by people around the world, in fact,
29
- it represents more than 1% of *all* gems downloaded.
27
+ Yes, you! Mail is used in countless apps by people around the world. It is,
28
+ like all open source software, a labour of love borne from our free time.
29
+ If you would like to say thanks, please dig in and contribute alongside us!
30
+ Triage and fix [GitHub issues](https://github.com/mikel/mail/issues), improve
31
+ our documentation, add new features—up to you! Thank you for pitching in.
30
32
 
31
- It is (like all open source software) a labour of love and something I am doing
32
- with my own free time. If you would like to say thanks, please feel free to
33
- [make a donation](http://www.pledgie.com/campaigns/8790) and feel free to send
34
- me a nice email :)
35
-
36
- <a href='http://www.pledgie.com/campaigns/8790'><img alt='Click here to lend your support to: mail and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/8790.png?skin_name=chrome' border='0' /></a>
37
33
 
38
34
  # Contents
39
35
  * [Compatibility](#compatibility)
@@ -46,15 +42,16 @@ me a nice email :)
46
42
  * [Encodings](#encodings)
47
43
  * [Contributing](#contributing)
48
44
  * [Usage](#usage)
49
- * [Core Extensions](#core-extensions)
50
45
  * [Excerpts from TREC Span Corpus 2005](#excerpts-from-trec-span-corpus-2005)
51
46
  * [License](#license)
52
47
 
53
48
  ## Compatibility
54
49
 
55
- Mail supports Ruby 1.8.7+, including JRuby and Rubinius.
50
+ Mail supports Ruby 2.5+, including JRuby and TruffleRuby.
51
+
52
+ As new versions of Ruby are released, Mail will be compatible with support for the "preview" and all "normal maintenance", "security maintenance" and the two most recent "end of life" versions listed at the [Ruby Maintenance Branches](https://www.ruby-lang.org/en/downloads/branches/) page. Pull requests to assist in adding support for new preview releases are more than welcome.
56
53
 
57
- Every Mail commit is tested by Travis on [all supported Ruby versions](https://github.com/mikel/mail/blob/master/.travis.yml).
54
+ Every Mail commit is tested by GitHub Actions on [all supported Ruby versions](https://github.com/mikel/mail/blob/master/.github/workflows/test.yml).
58
55
 
59
56
  ## Discussion
60
57
 
@@ -65,14 +62,14 @@ the [Google Group](http://groups.google.com/group/mail-ruby).
65
62
 
66
63
  * RFC5322 Support, Reading and Writing
67
64
  * RFC6532 Support, reading UTF-8 headers
68
- * RFC2045-2049 Support for multipart emails
69
- * Support for creating multipart alternate emails
70
- * Support for reading multipart/report emails &amp; getting details from such
65
+ * RFC2045-2049 Support for multipart email
66
+ * Support for creating multipart alternate email
67
+ * Support for reading multipart/report email &amp; getting details from such
71
68
  * Wrappers for File, Net/POP3, Net/SMTP
72
69
  * Auto-encoding of non-US-ASCII bodies and header fields
73
70
 
74
71
  Mail is RFC5322 and RFC6532 compliant now, that is, it can parse US-ASCII and UTF-8
75
- emails and generate US-ASCII emails. There are a few obsoleted syntax emails that
72
+ email and generate US-ASCII email. There are a few obsoleted email syntax that
76
73
  it will have problems with, but it also is quite robust, meaning, if it finds something
77
74
  it doesn't understand it will not crash, instead, it will skip the problem and keep
78
75
  parsing. In the case of a header it doesn't understand, it will initialise the header
@@ -101,7 +98,9 @@ the gem gets released.
101
98
 
102
99
  It also means you can be sure Mail will behave correctly.
103
100
 
104
- Note: If you care about core extensions (aka "monkey-patching"), please read the Core Extensions section near the end of this README.
101
+ You can run tests locally by running `bundle exec rspec`.
102
+
103
+ You can run tests on all supported Ruby versions by using [act](https://github.com/nektos/act).
105
104
 
106
105
  ## API Policy
107
106
 
@@ -150,13 +149,15 @@ I have tried to simplify it some:
150
149
 
151
150
  ## Contributing
152
151
 
153
- Please do! Contributing is easy in Mail. Please read the CONTRIBUTING.md document for more info
152
+ Please do! Contributing is easy in Mail. Please read the [CONTRIBUTING.md](CONTRIBUTING.md) document for more info.
154
153
 
155
154
  ## Usage
156
155
 
157
156
  All major mail functions should be able to happen from the Mail module.
158
157
  So, you should be able to just <code>require 'mail'</code> to get started.
159
158
 
159
+ `mail` is pretty well documented in its Ruby code. You can look it up e.g. at [rubydoc.info](https://www.rubydoc.info/gems/mail).
160
+
160
161
  ### Making an email
161
162
 
162
163
  ```ruby
@@ -290,12 +291,13 @@ mail.delivery_method :logger
290
291
  mail.delivery_method :logger, logger: other_logger, severity: :debug
291
292
  ```
292
293
 
293
- ### Getting Emails from a POP Server:
294
+ ### Getting Emails from a POP or IMAP Server:
294
295
 
295
296
  You can configure Mail to receive email using <code>retriever_method</code>
296
297
  within <code>Mail.defaults</code>:
297
298
 
298
299
  ```ruby
300
+ # e.g. POP3
299
301
  Mail.defaults do
300
302
  retriever_method :pop3, :address => "pop.gmail.com",
301
303
  :port => 995,
@@ -303,6 +305,15 @@ Mail.defaults do
303
305
  :password => '<password>',
304
306
  :enable_ssl => true
305
307
  end
308
+
309
+ # IMAP
310
+ Mail.defaults do
311
+ retriever_method :imap, :address => "imap.mailbox.org",
312
+ :port => 993,
313
+ :user_name => '<username>',
314
+ :password => '<password>',
315
+ :enable_ssl => true
316
+ end
306
317
  ```
307
318
 
308
319
  You can access incoming email in a number of ways.
@@ -445,7 +456,7 @@ Content-Transfer-Encoding: 7bit
445
456
  ```
446
457
 
447
458
  Mail inserts the content transfer encoding, the mime version,
448
- the content-id's and handles the content-type and boundary.
459
+ the content-IDs and handles the content-type and boundary.
449
460
 
450
461
  Mail assumes that if your text in the body is only us-ascii, that your
451
462
  transfer encoding is 7bit and it is text/plain. You can override this
@@ -639,6 +650,12 @@ describe "sending an email" do
639
650
  # ... or any attachment
640
651
  it { is_expected.to have_sent_email.with_attachments(any_attachment) }
641
652
 
653
+ # ... or attachment with filename
654
+ it { is_expected.to have_sent_email.with_attachments(an_attachment_with_filename('file.txt')) }
655
+
656
+ # ... or attachment with mime_type
657
+ it { is_expected.to have_sent_email.with_attachments(an_attachment_with_mime_type('application/pdf')) }
658
+
642
659
  # ... by array of attachments
643
660
  it { is_expected.to have_sent_email.with_attachments([my_attachment1, my_attachment2]) } #note that order is important
644
661
 
@@ -74,7 +74,7 @@ module Mail
74
74
  end
75
75
 
76
76
  if hash[:body].respond_to? :force_encoding and hash[:body].respond_to? :valid_encoding?
77
- if not hash[:body].valid_encoding? and default_values[:content_transfer_encoding].downcase == "binary"
77
+ if not hash[:body].valid_encoding? and default_values[:content_transfer_encoding].casecmp('binary').zero?
78
78
  hash[:body] = hash[:body].dup if hash[:body].frozen?
79
79
  hash[:body].force_encoding("BINARY")
80
80
  end
@@ -97,10 +97,7 @@ module Mail
97
97
  end
98
98
 
99
99
  def set_mime_type(filename)
100
- # Have to do this because MIME::Types is not Ruby 1.9 safe yet
101
- if RUBY_VERSION >= '1.9'
102
- filename = filename.encode(Encoding::UTF_8) if filename.respond_to?(:encode)
103
- end
100
+ filename = filename.encode(Encoding::UTF_8) if filename.respond_to?(:encode)
104
101
 
105
102
  @mime_type = MiniMime.lookup_by_filename(filename)
106
103
  @mime_type && @mime_type.content_type
data/lib/mail/body.rb CHANGED
@@ -50,6 +50,11 @@ module Mail
50
50
  set_charset
51
51
  end
52
52
 
53
+ def init_with(coder)
54
+ coder.map.each { |k, v| instance_variable_set(:"@#{k}", v) }
55
+ @parts = Mail::PartsList.new(coder['parts'])
56
+ end
57
+
53
58
  # Matches this body with another body. Also matches the decoded value of this
54
59
  # body with a string.
55
60
  #
@@ -133,12 +138,6 @@ module Mail
133
138
  @parts.sort!(@part_sort_order)
134
139
  end
135
140
 
136
- # Returns the raw source that the body was initialized with, without
137
- # any tampering
138
- def raw_source
139
- @raw_source
140
- end
141
-
142
141
  def negotiate_best_encoding(message_encoding, allowed_encodings = nil)
143
142
  Mail::Encodings::TransferEncoding.negotiate(message_encoding, encoding, raw_source, allowed_encodings)
144
143
  end
@@ -188,14 +187,6 @@ module Mail
188
187
  def to_s
189
188
  decoded
190
189
  end
191
-
192
- def charset
193
- @charset
194
- end
195
-
196
- def charset=( val )
197
- @charset = val
198
- end
199
190
 
200
191
  def encoding(val = nil)
201
192
  if val
@@ -214,45 +205,31 @@ module Mail
214
205
  end
215
206
  end
216
207
 
217
- # Returns the preamble (any text that is before the first MIME boundary)
218
- def preamble
219
- @preamble
220
- end
208
+ # Returns the raw source that the body was initialized with, without
209
+ # any tampering
210
+ attr_reader :raw_source
211
+
212
+ # Returns parts of the body
213
+ attr_reader :parts
214
+
215
+ # Returns and sets the original character encoding
216
+ attr_accessor :charset
217
+
218
+ # Returns and sets the preamble as a string (any text that is before the first MIME boundary)
219
+ attr_accessor :preamble
220
+
221
+ # Returns and sets the epilogue as a string (any text that is after the last MIME boundary)
222
+ attr_accessor :epilogue
223
+
224
+ # Returns and sets the boundary used by the body
225
+ # Allows you to change the boundary of this Body object
226
+ attr_accessor :boundary
221
227
 
222
- # Sets the preamble to a string (adds text before the first MIME boundary)
223
- def preamble=( val )
224
- @preamble = val
225
- end
226
-
227
- # Returns the epilogue (any text that is after the last MIME boundary)
228
- def epilogue
229
- @epilogue
230
- end
231
-
232
- # Sets the epilogue to a string (adds text after the last MIME boundary)
233
- def epilogue=( val )
234
- @epilogue = val
235
- end
236
-
237
228
  # Returns true if there are parts defined in the body
238
229
  def multipart?
239
230
  true unless parts.empty?
240
231
  end
241
-
242
- # Returns the boundary used by the body
243
- def boundary
244
- @boundary
245
- end
246
-
247
- # Allows you to change the boundary of this Body object
248
- def boundary=( val )
249
- @boundary = val
250
- end
251
232
 
252
- def parts
253
- @parts
254
- end
255
-
256
233
  def <<( val )
257
234
  if @parts
258
235
  @parts << val
@@ -16,9 +16,10 @@ module Mail
16
16
  control = control.dup.force_encoding(Encoding::BINARY)
17
17
  end
18
18
 
19
- CRLF = /\r?\n/
19
+ LAX_CRLF = /\r?\n/
20
20
  WSP = /[#{white_space}]/
21
- FWS = /#{CRLF}#{WSP}*/
21
+ FWS = /#{LAX_CRLF}#{WSP}*/
22
+ UNFOLD_WS = /#{LAX_CRLF}(#{WSP})/m
22
23
  TEXT = /[#{text}]/ # + obs-text
23
24
  FIELD_NAME = /[#{field_name}]+/
24
25
  FIELD_PREFIX = /\A(#{FIELD_NAME})/
@@ -26,7 +27,7 @@ module Mail
26
27
  FIELD_LINE = /^[#{field_name}]+:\s*.+$/
27
28
  FIELD_SPLIT = /^(#{FIELD_NAME})\s*:\s*(#{FIELD_BODY})?$/
28
29
  HEADER_LINE = /^([#{field_name}]+:\s*.+)$/
29
- HEADER_SPLIT = /#{CRLF}(?!#{WSP})/
30
+ HEADER_SPLIT = /#{LAX_CRLF}(?!#{WSP})/
30
31
 
31
32
  QP_UNSAFE = /[^#{qp_safe}]/
32
33
  QP_SAFE = /[#{qp_safe}]/
@@ -34,8 +35,28 @@ module Mail
34
35
  ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{sp}]/n
35
36
  PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
36
37
  TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{sp}]/n
37
- ENCODED_VALUE = /\=\?([^?]+)\?([QB])\?[^?]*?\?\=/mi
38
- FULL_ENCODED_VALUE = /(\=\?[^?]+\?[QB]\?[^?]*?\?\=)/mi
38
+
39
+ ENCODED_VALUE = %r{
40
+ \=\? # literal =?
41
+ ([^?]+) #
42
+ \? # literal ?
43
+ ([QB]) # either a "Q" or a "B"
44
+ \? # literal ?
45
+ .*? # lazily match all characters
46
+ \?\= # literal ?=
47
+ }mix # m is multi-line, i is case-insensitive, x is free-spacing
48
+
49
+ FULL_ENCODED_VALUE = %r{ # Identical to ENCODED_VALUE but captures the whole rather than components of
50
+ (
51
+ \=\? # literal =?
52
+ [^?]+ #
53
+ \? # literal ?
54
+ [QB] # either a "Q" or a "B"
55
+ \? # literal ?
56
+ .*? # lazily match all characters
57
+ \?\= # literal ?=
58
+ )
59
+ }mix # m is multi-line, i is case-insensitive, x is free-spacing
39
60
 
40
61
  EMPTY = ''
41
62
  SPACE = ' '
@@ -43,6 +64,7 @@ module Mail
43
64
  HYPHEN = '-'
44
65
  COLON = ':'
45
66
  ASTERISK = '*'
67
+ CRLF = "\r\n"
46
68
  CR = "\r"
47
69
  LF = "\n"
48
70
  CR_ENCODED = "=0D"
@@ -1,27 +1,27 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
3
  require 'mail/parsers/address_lists_parser'
4
+ require 'mail/constants'
5
+ require 'mail/utilities'
4
6
 
5
7
  module Mail
8
+ # Mail::Address handles all email addresses in Mail. It takes an email address string
9
+ # and parses it, breaking it down into its component parts and allowing you to get the
10
+ # address, comments, display name, name, local part, domain part and fully formatted
11
+ # address.
12
+ #
13
+ # Mail::Address requires a correctly formatted email address per RFC2822 or RFC822. It
14
+ # handles all obsolete versions including obsolete domain routing on the local part.
15
+ #
16
+ # a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
17
+ # a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
18
+ # a.address #=> 'mikel@test.lindsaar.net'
19
+ # a.display_name #=> 'Mikel Lindsaar'
20
+ # a.local #=> 'mikel'
21
+ # a.domain #=> 'test.lindsaar.net'
22
+ # a.comments #=> ['My email address']
23
+ # a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
6
24
  class Address
7
- include Mail::Utilities
8
-
9
- # Mail::Address handles all email addresses in Mail. It takes an email address string
10
- # and parses it, breaking it down into its component parts and allowing you to get the
11
- # address, comments, display name, name, local part, domain part and fully formatted
12
- # address.
13
- #
14
- # Mail::Address requires a correctly formatted email address per RFC2822 or RFC822. It
15
- # handles all obsolete versions including obsolete domain routing on the local part.
16
- #
17
- # a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
18
- # a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
19
- # a.address #=> 'mikel@test.lindsaar.net'
20
- # a.display_name #=> 'Mikel Lindsaar'
21
- # a.local #=> 'mikel'
22
- # a.domain #=> 'test.lindsaar.net'
23
- # a.comments #=> ['My email address']
24
- # a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
25
25
  def initialize(value = nil)
26
26
  if value.nil?
27
27
  @parsed = false
@@ -47,11 +47,11 @@ module Mail
47
47
  def format(output_type = :decode)
48
48
  parse unless @parsed
49
49
  if @data.nil?
50
- EMPTY
50
+ Constants::EMPTY
51
51
  elsif name = display_name(output_type)
52
- [quote_phrase(name), "<#{address(output_type)}>", format_comments].compact.join(SPACE)
52
+ [Utilities.quote_phrase(name), "<#{address(output_type)}>", format_comments].compact.join(Constants::SPACE)
53
53
  elsif a = address(output_type)
54
- [a, format_comments].compact.join(SPACE)
54
+ [a, format_comments].compact.join(Constants::SPACE)
55
55
  else
56
56
  raw
57
57
  end
@@ -135,7 +135,7 @@ module Mail
135
135
  if comments.nil? || comments.none?
136
136
  nil
137
137
  else
138
- comments.map { |c| c.squeeze(SPACE) }
138
+ comments.map { |c| c.squeeze(Constants::SPACE) }
139
139
  end
140
140
  end
141
141
 
@@ -198,7 +198,7 @@ module Mail
198
198
  def strip_all_comments(string)
199
199
  unless Utilities.blank?(comments)
200
200
  comments.each do |comment|
201
- string = string.gsub("(#{comment})", EMPTY)
201
+ string = string.gsub("(#{comment})", Constants::EMPTY)
202
202
  end
203
203
  end
204
204
  string.strip
@@ -208,7 +208,7 @@ module Mail
208
208
  unless Utilities.blank?(comments)
209
209
  comments.each do |comment|
210
210
  if @data.domain && @data.domain.include?("(#{comment})")
211
- value = value.gsub("(#{comment})", EMPTY)
211
+ value = value.gsub("(#{comment})", Constants::EMPTY)
212
212
  end
213
213
  end
214
214
  end
@@ -228,15 +228,15 @@ module Mail
228
228
  if display_name
229
229
  str = display_name
230
230
  elsif comments
231
- str = "(#{comments.join(SPACE).squeeze(SPACE)})"
231
+ str = "(#{comments.join(Constants::SPACE).squeeze(Constants::SPACE)})"
232
232
  end
233
233
 
234
- unparen(str) unless Utilities.blank?(str)
234
+ Utilities.unparen(str) unless Utilities.blank?(str)
235
235
  end
236
236
 
237
237
  def format_comments
238
238
  if comments
239
- comment_text = comments.map {|c| escape_paren(c) }.join(SPACE).squeeze(SPACE)
239
+ comment_text = comments.map {|c| Utilities.escape_paren(c) }.join(Constants::SPACE).squeeze(Constants::SPACE)
240
240
  @format_comments ||= "(#{comment_text})"
241
241
  else
242
242
  nil
@@ -3,7 +3,7 @@
3
3
  require 'mail/parsers/address_lists_parser'
4
4
 
5
5
  module Mail
6
- class AddressList # :nodoc:
6
+ class AddressList #:nodoc:
7
7
  attr_reader :addresses, :group_names
8
8
 
9
9
  # Mail::AddressList is the class that parses To, From and other address fields from
@@ -3,7 +3,7 @@
3
3
  require 'mail/parsers/content_disposition_parser'
4
4
 
5
5
  module Mail
6
- class ContentDispositionElement # :nodoc:
6
+ class ContentDispositionElement #:nodoc:
7
7
  attr_reader :disposition_type, :parameters
8
8
 
9
9
  def initialize(string)
@@ -3,7 +3,7 @@
3
3
  require 'mail/parsers/content_location_parser'
4
4
 
5
5
  module Mail
6
- class ContentLocationElement # :nodoc:
6
+ class ContentLocationElement #:nodoc:
7
7
  attr_reader :location
8
8
 
9
9
  def initialize(string)
@@ -3,7 +3,7 @@
3
3
  require 'mail/parsers/content_transfer_encoding_parser'
4
4
 
5
5
  module Mail
6
- class ContentTransferEncodingElement
6
+ class ContentTransferEncodingElement #:nodoc:
7
7
  attr_reader :encoding
8
8
 
9
9
  def initialize(string)
@@ -3,7 +3,7 @@
3
3
  require 'mail/parsers/content_type_parser'
4
4
 
5
5
  module Mail
6
- class ContentTypeElement # :nodoc:
6
+ class ContentTypeElement #:nodoc:
7
7
  attr_reader :main_type, :sub_type, :parameters
8
8
 
9
9
  def initialize(string)
@@ -14,8 +14,12 @@ module Mail
14
14
  end
15
15
 
16
16
  private
17
- def cleaned(string)
18
- string =~ /(.+);\s*$/ ? $1 : string
19
- end
17
+ def cleaned(string)
18
+ if string =~ /;\s*$/
19
+ $`
20
+ else
21
+ string
22
+ end
23
+ end
20
24
  end
21
25
  end
@@ -3,7 +3,7 @@
3
3
  require 'mail/parsers/date_time_parser'
4
4
 
5
5
  module Mail
6
- class DateTimeElement # :nodoc:
6
+ class DateTimeElement #:nodoc:
7
7
  attr_reader :date_string, :time_string
8
8
 
9
9
  def initialize(string)
@@ -4,13 +4,13 @@ require 'mail/parsers/envelope_from_parser'
4
4
  require 'date'
5
5
 
6
6
  module Mail
7
- class EnvelopeFromElement
7
+ class EnvelopeFromElement #:nodoc:
8
8
  attr_reader :date_time, :address
9
9
 
10
10
  def initialize(string)
11
11
  envelope_from = Mail::Parsers::EnvelopeFromParser.parse(string)
12
12
  @address = envelope_from.address
13
- @date_time = ::DateTime.parse(envelope_from.ctime_date)
13
+ @date_time = ::DateTime.parse(envelope_from.ctime_date) if envelope_from.ctime_date
14
14
  end
15
15
 
16
16
  # RFC 4155:
@@ -19,15 +19,21 @@ module Mail
19
19
  # traditional UNIX 'ctime' output sans timezone (note that the
20
20
  # use of UTC precludes the need for a timezone indicator);
21
21
  def formatted_date_time
22
- if date_time.respond_to?(:ctime)
23
- date_time.ctime
24
- else
25
- date_time.strftime '%a %b %e %T %Y'
22
+ if date_time
23
+ if date_time.respond_to?(:ctime)
24
+ date_time.ctime
25
+ else
26
+ date_time.strftime '%a %b %e %T %Y'
27
+ end
26
28
  end
27
29
  end
28
30
 
29
31
  def to_s
30
- "#{address} #{formatted_date_time}"
32
+ if date_time
33
+ "#{address} #{formatted_date_time}"
34
+ else
35
+ address
36
+ end
31
37
  end
32
38
  end
33
39
  end
@@ -1,13 +1,18 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
3
  require 'mail/parsers/message_ids_parser'
4
+ require 'mail/utilities'
4
5
 
5
6
  module Mail
6
- class MessageIdsElement
7
+ class MessageIdsElement #:nodoc:
8
+ def self.parse(string)
9
+ new(string).tap(&:message_ids)
10
+ end
11
+
7
12
  attr_reader :message_ids
8
13
 
9
14
  def initialize(string)
10
- @message_ids = Mail::Parsers::MessageIdsParser.parse(string).message_ids.map { |msg_id| clean_msg_id(msg_id) }
15
+ @message_ids = parse(string)
11
16
  end
12
17
 
13
18
  def message_id
@@ -15,8 +20,12 @@ module Mail
15
20
  end
16
21
 
17
22
  private
18
- def clean_msg_id(val)
19
- val =~ /.*<(.*)>.*/ ? $1 : val
20
- end
23
+ def parse(string)
24
+ if Utilities.blank? string
25
+ []
26
+ else
27
+ Mail::Parsers::MessageIdsParser.parse(string).message_ids
28
+ end
29
+ end
21
30
  end
22
31
  end
@@ -3,7 +3,7 @@
3
3
  require 'mail/parsers/mime_version_parser'
4
4
 
5
5
  module Mail
6
- class MimeVersionElement
6
+ class MimeVersionElement #:nodoc:
7
7
  attr_reader :major, :minor
8
8
 
9
9
  def initialize(string)
@@ -4,11 +4,16 @@ require 'mail/parsers/phrase_lists_parser'
4
4
  require 'mail/utilities'
5
5
 
6
6
  module Mail
7
- class PhraseList
7
+ class PhraseList #:nodoc:
8
8
  attr_reader :phrases
9
9
 
10
10
  def initialize(string)
11
- @phrases = Mail::Parsers::PhraseListsParser.parse(string).phrases.map { |p| Mail::Utilities.unquote(p) }
11
+ @phrases =
12
+ if Utilities.blank? string
13
+ []
14
+ else
15
+ Mail::Parsers::PhraseListsParser.parse(string).phrases.map { |p| Mail::Utilities.unquote(p) }
16
+ end
12
17
  end
13
18
  end
14
19
  end