mail 2.6.4 → 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 (162) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +74 -98
  3. data/lib/mail/attachments_list.rb +9 -5
  4. data/lib/mail/body.rb +42 -36
  5. data/lib/mail/check_delivery_params.rb +49 -10
  6. data/lib/mail/configuration.rb +2 -0
  7. data/lib/mail/core_extensions/smtp.rb +19 -16
  8. data/lib/mail/core_extensions/string.rb +0 -4
  9. data/lib/mail/elements/address.rb +37 -26
  10. data/lib/mail/elements/address_list.rb +10 -18
  11. data/lib/mail/elements/content_disposition_element.rb +8 -15
  12. data/lib/mail/elements/content_location_element.rb +5 -10
  13. data/lib/mail/elements/content_transfer_encoding_element.rb +5 -10
  14. data/lib/mail/elements/content_type_element.rb +8 -19
  15. data/lib/mail/elements/date_time_element.rb +6 -14
  16. data/lib/mail/elements/envelope_from_element.rb +14 -21
  17. data/lib/mail/elements/message_ids_element.rb +8 -12
  18. data/lib/mail/elements/mime_version_element.rb +6 -14
  19. data/lib/mail/elements/phrase_list.rb +6 -9
  20. data/lib/mail/elements/received_element.rb +9 -15
  21. data/lib/mail/encodings/7bit.rb +5 -15
  22. data/lib/mail/encodings/8bit.rb +2 -21
  23. data/lib/mail/encodings/base64.rb +11 -12
  24. data/lib/mail/encodings/binary.rb +3 -22
  25. data/lib/mail/encodings/identity.rb +24 -0
  26. data/lib/mail/encodings/quoted_printable.rb +6 -6
  27. data/lib/mail/encodings/transfer_encoding.rb +38 -29
  28. data/lib/mail/encodings/unix_to_unix.rb +2 -1
  29. data/lib/mail/encodings.rb +99 -43
  30. data/lib/mail/envelope.rb +1 -1
  31. data/lib/mail/field.rb +94 -59
  32. data/lib/mail/fields/bcc_field.rb +2 -2
  33. data/lib/mail/fields/cc_field.rb +1 -1
  34. data/lib/mail/fields/comments_field.rb +1 -1
  35. data/lib/mail/fields/common/address_container.rb +2 -2
  36. data/lib/mail/fields/common/common_address.rb +32 -7
  37. data/lib/mail/fields/common/common_field.rb +1 -10
  38. data/lib/mail/fields/common/parameter_hash.rb +1 -1
  39. data/lib/mail/fields/content_description_field.rb +1 -1
  40. data/lib/mail/fields/content_disposition_field.rb +3 -3
  41. data/lib/mail/fields/content_id_field.rb +2 -2
  42. data/lib/mail/fields/content_location_field.rb +1 -1
  43. data/lib/mail/fields/content_transfer_encoding_field.rb +1 -1
  44. data/lib/mail/fields/content_type_field.rb +3 -8
  45. data/lib/mail/fields/date_field.rb +2 -3
  46. data/lib/mail/fields/from_field.rb +1 -1
  47. data/lib/mail/fields/in_reply_to_field.rb +1 -1
  48. data/lib/mail/fields/keywords_field.rb +1 -1
  49. data/lib/mail/fields/message_id_field.rb +1 -1
  50. data/lib/mail/fields/mime_version_field.rb +1 -1
  51. data/lib/mail/fields/optional_field.rb +4 -1
  52. data/lib/mail/fields/received_field.rb +1 -1
  53. data/lib/mail/fields/references_field.rb +1 -1
  54. data/lib/mail/fields/reply_to_field.rb +1 -1
  55. data/lib/mail/fields/resent_bcc_field.rb +1 -1
  56. data/lib/mail/fields/resent_cc_field.rb +1 -1
  57. data/lib/mail/fields/resent_date_field.rb +0 -1
  58. data/lib/mail/fields/resent_from_field.rb +1 -1
  59. data/lib/mail/fields/resent_message_id_field.rb +1 -1
  60. data/lib/mail/fields/resent_sender_field.rb +1 -1
  61. data/lib/mail/fields/resent_to_field.rb +1 -1
  62. data/lib/mail/fields/return_path_field.rb +1 -1
  63. data/lib/mail/fields/sender_field.rb +1 -1
  64. data/lib/mail/fields/subject_field.rb +1 -1
  65. data/lib/mail/fields/to_field.rb +1 -1
  66. data/lib/mail/fields/unstructured_field.rb +21 -4
  67. data/lib/mail/header.rb +10 -8
  68. data/lib/mail/mail.rb +2 -10
  69. data/lib/mail/matchers/has_sent_mail.rb +21 -1
  70. data/lib/mail/message.rb +77 -66
  71. data/lib/mail/multibyte/chars.rb +31 -30
  72. data/lib/mail/multibyte.rb +64 -15
  73. data/lib/mail/network/delivery_methods/exim.rb +6 -10
  74. data/lib/mail/network/delivery_methods/file_delivery.rb +4 -8
  75. data/lib/mail/network/delivery_methods/logger_delivery.rb +37 -0
  76. data/lib/mail/network/delivery_methods/sendmail.rb +16 -11
  77. data/lib/mail/network/delivery_methods/smtp.rb +59 -53
  78. data/lib/mail/network/delivery_methods/smtp_connection.rb +10 -6
  79. data/lib/mail/network/delivery_methods/test_mailer.rb +5 -8
  80. data/lib/mail/network/retriever_methods/imap.rb +18 -5
  81. data/lib/mail/network/retriever_methods/pop3.rb +3 -1
  82. data/lib/mail/network/retriever_methods/test_retriever.rb +1 -1
  83. data/lib/mail/network.rb +1 -0
  84. data/lib/mail/parser_tools.rb +15 -0
  85. data/lib/mail/parsers/address_lists_parser.rb +33186 -112
  86. data/lib/mail/parsers/address_lists_parser.rl +172 -0
  87. data/lib/mail/parsers/content_disposition_parser.rb +888 -55
  88. data/lib/mail/parsers/content_disposition_parser.rl +82 -0
  89. data/lib/mail/parsers/content_location_parser.rb +800 -23
  90. data/lib/mail/parsers/content_location_parser.rl +71 -0
  91. data/lib/mail/parsers/content_transfer_encoding_parser.rb +510 -22
  92. data/lib/mail/parsers/content_transfer_encoding_parser.rl +64 -0
  93. data/lib/mail/parsers/content_type_parser.rb +1032 -54
  94. data/lib/mail/parsers/content_type_parser.rl +83 -0
  95. data/lib/mail/parsers/date_time_parser.rb +873 -26
  96. data/lib/mail/parsers/date_time_parser.rl +62 -0
  97. data/lib/mail/parsers/envelope_from_parser.rb +3564 -36
  98. data/lib/mail/parsers/envelope_from_parser.rl +82 -0
  99. data/lib/mail/parsers/message_ids_parser.rb +2843 -25
  100. data/lib/mail/parsers/message_ids_parser.rl +82 -0
  101. data/lib/mail/parsers/mime_version_parser.rb +493 -26
  102. data/lib/mail/parsers/mime_version_parser.rl +61 -0
  103. data/lib/mail/parsers/phrase_lists_parser.rb +874 -19
  104. data/lib/mail/parsers/phrase_lists_parser.rl +83 -0
  105. data/lib/mail/parsers/received_parser.rb +8743 -38
  106. data/lib/mail/parsers/received_parser.rl +84 -0
  107. data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
  108. data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
  109. data/lib/mail/parsers/rfc2045_mime.rl +16 -0
  110. data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
  111. data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  112. data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
  113. data/lib/mail/parsers/rfc5322.rl +59 -0
  114. data/lib/mail/parsers/rfc5322_address.rl +72 -0
  115. data/lib/mail/parsers/{ragel/date_time.rl → rfc5322_date_time.rl} +8 -1
  116. data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
  117. data/lib/mail/parsers.rb +16 -24
  118. data/lib/mail/part.rb +1 -1
  119. data/lib/mail/parts_list.rb +5 -6
  120. data/lib/mail/utilities.rb +63 -18
  121. data/lib/mail/version.rb +2 -2
  122. data/lib/mail/version_specific/ruby_1_8.rb +40 -3
  123. data/lib/mail/version_specific/ruby_1_9.rb +64 -9
  124. data/lib/mail.rb +3 -16
  125. metadata +30 -53
  126. data/CHANGELOG.rdoc +0 -787
  127. data/CONTRIBUTING.md +0 -60
  128. data/Dependencies.txt +0 -2
  129. data/Gemfile +0 -11
  130. data/Rakefile +0 -29
  131. data/TODO.rdoc +0 -9
  132. data/lib/mail/core_extensions/string/access.rb +0 -146
  133. data/lib/mail/core_extensions/string/multibyte.rb +0 -79
  134. data/lib/mail/multibyte/exceptions.rb +0 -9
  135. data/lib/mail/parsers/ragel/common.rl +0 -185
  136. data/lib/mail/parsers/ragel/parser_info.rb +0 -61
  137. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +0 -14864
  138. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +0 -37
  139. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +0 -751
  140. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +0 -37
  141. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +0 -614
  142. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +0 -37
  143. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +0 -447
  144. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +0 -37
  145. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +0 -825
  146. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +0 -37
  147. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +0 -817
  148. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +0 -37
  149. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +0 -2149
  150. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +0 -37
  151. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +0 -1570
  152. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +0 -37
  153. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +0 -440
  154. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +0 -37
  155. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +0 -564
  156. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +0 -37
  157. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +0 -51
  158. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +0 -5144
  159. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +0 -37
  160. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +0 -37
  161. data/lib/mail/parsers/ragel/ruby.rb +0 -40
  162. data/lib/mail/parsers/ragel.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f91f133d2e44832ecef1cb4bfe9cc57391aedf84
4
- data.tar.gz: 23d0cdbc09cdbaafee76b01d7c3820a6c0dfb6d1
3
+ metadata.gz: 0f77ef2d4e2ecc02b59f5431cd56e3c0a5569262
4
+ data.tar.gz: a6e4a0ee6b7d2d1a824578a43a5c73893ae3fa10
5
5
  SHA512:
6
- metadata.gz: c788407da309561bee6a59ec746efeea7c0cc8633206eb2085f08ad6b161df92475109a988de748e554248d2ca47e6cd31c3fd0394d0eddac5950e7bb28783a8
7
- data.tar.gz: 55b70f9d539420d254373c7abfccf6bc85228f34c38696086be363a36fb4f966415238aaa8e9ec9e6eed02207af2a3940b9f85c5f3076e735cd19e095764abc2
6
+ metadata.gz: 70f3d73bb71de6e3d6121df0e93cd3909fb35eef6716c0597803a67ee341445385951dc662901dce2e806840c399d1f6ea0015987b2944b9fb24f9973a8e97af
7
+ data.tar.gz: 0d7283e6e57f4600704b9d9e45ae17e77e8105db42a394174217c7f488e81ac4598fef6492e85e24a8e763ceb302ee3ee6754fa1bf3bf9777bfa37a707157d4b
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
- Mail [![Build Status](https://travis-ci.org/mikel/mail.png?branch=master)](https://travis-ci.org/mikel/mail)
2
- ====
1
+ # Mail [![Build Status](https://travis-ci.org/mikel/mail.png?branch=master)](https://travis-ci.org/mikel/mail)
3
2
 
4
- Introduction
5
- ------------
3
+ ## Introduction
6
4
 
7
5
  Mail is an internet library for Ruby that is designed to handle emails
8
6
  generation, parsing and sending in a simple, rubyesque manner.
@@ -25,8 +23,7 @@ Finally, Mail has been designed with a very simple object oriented system
25
23
  that really opens up the email messages you are parsing, if you know what
26
24
  you are doing, you can fiddle with every last bit of your email directly.
27
25
 
28
- Donations
29
- -------------
26
+ ## Donations
30
27
 
31
28
  Mail has been downloaded millions of times, by people around the world, in fact,
32
29
  it represents more than 1% of *all* gems downloaded.
@@ -38,52 +35,48 @@ me a nice email :)
38
35
 
39
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>
40
37
 
38
+ # Contents
39
+ * [Compatibility](#compatibility)
40
+ * [Discussion](#discussion)
41
+ * [Current Capabilities of Mail](#current-capabilities-of-mail)
42
+ * [Roadmap](#roadmap)
43
+ * [Testing Policy](#testing-policy)
44
+ * [API Policy](#api-policy)
45
+ * [Installation](#installation)
46
+ * [Encodings](#encodings)
47
+ * [Contributing](#contributing)
48
+ * [Usage](#usage)
49
+ * [Core Extensions](#core-extensions)
50
+ * [Excerpts from TREC Span Corpus 2005](#excerpts-from-trec-span-corpus-2005)
51
+ * [License](#license)
41
52
 
42
- Compatibility
43
- -------------
53
+ ## Compatibility
44
54
 
45
- Every Mail commit is tested by Travis on the [following platforms](https://github.com/mikel/mail/blob/master/.travis.yml)
55
+ Mail supports Ruby 1.8.7+, including JRuby and Rubinius.
46
56
 
47
- * ruby-1.8.7 [ i686 ]
48
- * ruby-1.9.2 [ x86_64 ]
49
- * ruby-1.9.3 [ x86_64 ]
50
- * ruby-2.0.0 [ x86_64 ]
51
- * ruby-2.1.2 [ x86_64 ]
52
- * ruby-head [ x86_64 ]
53
- * jruby [ x86_64 ]
54
- * jruby-head [ x86_64 ]
55
- * rbx-2 [ x86_64 ]
57
+ Every Mail commit is tested by Travis on [all supported Ruby versions](https://github.com/mikel/mail/blob/master/.travis.yml).
56
58
 
57
- Testing a specific mime type (needed for 1.8.7 for example) can be done manually with:
58
-
59
- ```sh
60
- BUNDLE_GEMFILE=gemfiles/mime_types_1.16.gemfile (bundle check || bundle) && rake
61
- ```
62
-
63
- Discussion
64
- ----------
59
+ ## Discussion
65
60
 
66
61
  If you want to discuss mail with like minded individuals, please subscribe to
67
62
  the [Google Group](http://groups.google.com/group/mail-ruby).
68
63
 
69
- Current Capabilities of Mail
70
- ----------------------------
64
+ ## Current Capabilities of Mail
71
65
 
72
- * RFC2822 Support, Reading and Writing
66
+ * RFC5322 Support, Reading and Writing
67
+ * RFC6532 Support, reading UTF-8 headers
73
68
  * RFC2045-2049 Support for multipart emails
74
69
  * Support for creating multipart alternate emails
75
70
  * Support for reading multipart/report emails &amp; getting details from such
76
- * Support for multibyte emails - needs quite a lot of work and testing
77
71
  * Wrappers for File, Net/POP3, Net/SMTP
78
- * Auto encoding of non US-ASCII header fields
79
- * Auto encoding of non US-ASCII bodies
72
+ * Auto-encoding of non-US-ASCII bodies and header fields
80
73
 
81
- Mail is RFC2822 compliant now, that is, it can parse and generate valid US-ASCII
82
- emails. There are a few obsoleted syntax emails that it will have problems with, but
83
- it also is quite robust, meaning, if it finds something it doesn't understand it will
84
- not crash, instead, it will skip the problem and keep parsing. In the case of a header
85
- it doesn't understand, it will initialise the header as an optional unstructured
86
- field and continue parsing.
74
+ 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
76
+ it will have problems with, but it also is quite robust, meaning, if it finds something
77
+ it doesn't understand it will not crash, instead, it will skip the problem and keep
78
+ parsing. In the case of a header it doesn't understand, it will initialise the header
79
+ as an optional unstructured field and continue parsing.
87
80
 
88
81
  This means Mail won't (ever) crunch your data (I think).
89
82
 
@@ -91,16 +84,14 @@ You can also create MIME emails. There are helper methods for making a
91
84
  multipart/alternate email for text/plain and text/html (the most common pair)
92
85
  and you can manually create any other type of MIME email.
93
86
 
94
- Roadmap
95
- -------
87
+ ## Roadmap
96
88
 
97
89
  Next TODO:
98
90
 
99
91
  * Improve MIME support for character sets in headers, currently works, mostly, needs
100
92
  refinement.
101
93
 
102
- Testing Policy
103
- --------------
94
+ ## Testing Policy
104
95
 
105
96
  Basically... we do BDD on Mail. No method gets written in Mail without a
106
97
  corresponding or covering spec. We expect as a minimum 100% coverage
@@ -112,23 +103,20 @@ It also means you can be sure Mail will behave correctly.
112
103
 
113
104
  Note: If you care about core extensions (aka "monkey-patching"), please read the Core Extensions section near the end of this README.
114
105
 
115
- API Policy
116
- ----------
106
+ ## API Policy
117
107
 
118
108
  No API removals within a single point release. All removals to be deprecated with
119
109
  warnings for at least one MINOR point release before removal.
120
110
 
121
111
  Also, all private or protected methods to be declared as such - though this is still I/P.
122
112
 
123
- Installation
124
- ------------
113
+ ## Installation
125
114
 
126
115
  Installation is fairly simple, I host mail on rubygems, so you can just do:
127
116
 
128
117
  # gem install mail
129
118
 
130
- Encodings
131
- ---------
119
+ ## Encodings
132
120
 
133
121
  If you didn't know, handling encodings in Emails is not as straight forward as you
134
122
  would hope.
@@ -160,13 +148,11 @@ I have tried to simplify it some:
160
148
  provide encoded parameter values when you call the parameter names through the
161
149
  <code>object.parameters['<parameter_name>']</code> method call.
162
150
 
163
- Contributing
164
- ------------
151
+ ## Contributing
165
152
 
166
153
  Please do! Contributing is easy in Mail. Please read the CONTRIBUTING.md document for more info
167
154
 
168
- Usage
169
- -----
155
+ ## Usage
170
156
 
171
157
  All major mail functions should be able to happen from the Mail module.
172
158
  So, you should be able to just <code>require 'mail'</code> to get started.
@@ -234,7 +220,7 @@ what you are doing.
234
220
  ### Sending an email:
235
221
 
236
222
  Mail defaults to sending via SMTP to local host port 25. If you have a
237
- sendmail or postfix daemon running on on this port, sending email is as
223
+ sendmail or postfix daemon running on this port, sending email is as
238
224
  easy as:
239
225
 
240
226
  ```ruby
@@ -294,7 +280,17 @@ mail.delivery_method :exim, :location => "/usr/bin/exim"
294
280
  mail.deliver
295
281
  ```
296
282
 
297
- ### Getting emails from a pop server:
283
+ Mail may be "delivered" to a logfile, too, for development and testing:
284
+
285
+ ```ruby
286
+ # Delivers by logging the encoded message to $stdout
287
+ mail.delivery_method :logger
288
+
289
+ # Delivers to an existing logger at :debug severity
290
+ mail.delivery_method :logger, logger: other_logger, severity: :debug
291
+ ```
292
+
293
+ ### Getting Emails from a POP Server:
298
294
 
299
295
  You can configure Mail to receive email using <code>retriever_method</code>
300
296
  within <code>Mail.defaults</code>:
@@ -347,7 +343,7 @@ mail.cc #=> 'sam@test.lindsaar.net'
347
343
  mail.subject #=> "This is the subject"
348
344
  mail.date.to_s #=> '21 Nov 1997 09:55:06 -0600'
349
345
  mail.message_id #=> '<4D6AA7EB.6490534@xxx.xxx>'
350
- mail.body.decoded #=> 'This is the body of the email...
346
+ mail.decoded #=> 'This is the body of the email...
351
347
  ```
352
348
 
353
349
  Many more methods available.
@@ -373,7 +369,7 @@ is another message which can have many or no parts.
373
369
  A message will only have parts if it is a multipart/mixed or multipart/related
374
370
  content type and has a boundary defined.
375
371
 
376
- ### Testing and extracting attachments
372
+ ### Testing and Extracting Attachments
377
373
  ```ruby
378
374
  mail.attachments.each do | attachment |
379
375
  # Attachments is an AttachmentsList object containing a
@@ -382,14 +378,14 @@ mail.attachments.each do | attachment |
382
378
  # extracting images for example...
383
379
  filename = attachment.filename
384
380
  begin
385
- File.open(images_dir + filename, "w+b", 0644) {|f| f.write attachment.body.decoded}
381
+ File.open(images_dir + filename, "w+b", 0644) {|f| f.write attachment.decoded}
386
382
  rescue => e
387
383
  puts "Unable to save data for #{filename} because #{e.message}"
388
384
  end
389
385
  end
390
386
  end
391
387
  ```
392
- ### Writing and sending a multipart/alternative (html and text) email
388
+ ### Writing and Sending a Multipart/Alternative (HTML and Text) Email
393
389
 
394
390
  Mail makes some basic assumptions and makes doing the common thing as
395
391
  simple as possible.... (asking a lot from a mail library)
@@ -455,7 +451,7 @@ Mail assumes that if your text in the body is only us-ascii, that your
455
451
  transfer encoding is 7bit and it is text/plain. You can override this
456
452
  by explicitly declaring it.
457
453
 
458
- ### Making Multipart/Alternate, without a block
454
+ ### Making Multipart/Alternate, Without a Block
459
455
 
460
456
  You don't have to use a block with the text and html part included, you
461
457
  can just do it declaratively. However, you need to add Mail::Parts to
@@ -483,7 +479,7 @@ mail.html_part = html_part
483
479
 
484
480
  Results in the same email as done using the block form
485
481
 
486
- ### Getting error reports from an email:
482
+ ### Getting Error Reports from an Email:
487
483
 
488
484
  ```ruby
489
485
  @mail = Mail.read('/path/to/bounce_message.eml')
@@ -527,7 +523,6 @@ than mail (this should be rarely needed)
527
523
 
528
524
  ```ruby
529
525
  @mail = Mail.new
530
- file_data = File.read('path/to/myfile.pdf')
531
526
  @mail.attachments['myfile.pdf'] = { :mime_type => 'application/x-pdf',
532
527
  :content => File.read('path/to/myfile.pdf') }
533
528
  @mail.parts.first.mime_type #=> 'application/x-pdf'
@@ -560,8 +555,7 @@ end
560
555
  ```
561
556
  See "Testing and extracting attachments" above for more details.
562
557
 
563
- Using Mail with Testing or Spec'ing Libraries
564
- ---------------------------------------------
558
+ ## Using Mail with Testing or Spec'ing Libraries
565
559
 
566
560
  If mail is part of your system, you'll need a way to test it without actually
567
561
  sending emails, the TestMailer can do this for you.
@@ -611,70 +605,53 @@ describe "sending an email" do
611
605
  end
612
606
  end
613
607
 
614
- it { should have_sent_email } # passes if any email at all was sent
608
+ it { is_expected.to have_sent_email } # passes if any email at all was sent
615
609
 
616
- it { should have_sent_email.from('you@you.com') }
617
- it { should have_sent_email.to('mike1@me.com') }
610
+ it { is_expected.to have_sent_email.from('you@you.com') }
611
+ it { is_expected.to have_sent_email.to('mike1@me.com') }
618
612
 
619
613
  # can specify a list of recipients...
620
- it { should have_sent_email.to(['mike1@me.com', 'mike2@me.com']) }
614
+ it { is_expected.to have_sent_email.to(['mike1@me.com', 'mike2@me.com']) }
621
615
 
622
616
  # ...or chain recipients together
623
- it { should have_sent_email.to('mike1@me.com').to('mike2@me.com') }
617
+ it { is_expected.to have_sent_email.to('mike1@me.com').to('mike2@me.com') }
624
618
 
625
- it { should have_sent_email.with_subject('testing') }
619
+ it { is_expected.to have_sent_email.with_subject('testing') }
626
620
 
627
- it { should have_sent_email.with_body('hello') }
621
+ it { is_expected.to have_sent_email.with_body('hello') }
628
622
 
629
623
  # Can match subject or body with a regex
630
624
  # (or anything that responds_to? :match)
631
625
 
632
- it { should have_sent_email.matching_subject(/test(ing)?/) }
633
- it { should have_sent_email.matching_body(/h(a|e)llo/) }
626
+ it { is_expected.to have_sent_email.matching_subject(/test(ing)?/) }
627
+ it { is_expected.to have_sent_email.matching_body(/h(a|e)llo/) }
634
628
 
635
629
  # Can chain together modifiers
636
630
  # Note that apart from recipients, repeating a modifier overwrites old value.
637
631
 
638
- it { should have_sent_email.from('you@you.com').to('mike1@me.com').matching_body(/hell/)
632
+ it { is_expected.to have_sent_email.from('you@you.com').to('mike1@me.com').matching_body(/hell/)
639
633
 
640
634
  # test for attachments
641
635
 
642
636
  # ... by specific attachment
643
- it { should_have_sent_email.with_attachments(my_attachment) }
637
+ it { is_expected.to have_sent_email.with_attachments(my_attachment) }
644
638
 
645
639
  # ... or any attachment
646
- it { should_have_sent_email.with_attachments(any_attachment) }
640
+ it { is_expected.to have_sent_email.with_attachments(any_attachment) }
647
641
 
648
642
  # ... by array of attachments
649
- it { should_have_sent_email.with_attachments([my_attachment1, my_attachment2]) } #note that order is important
643
+ it { is_expected.to have_sent_email.with_attachments([my_attachment1, my_attachment2]) } #note that order is important
650
644
 
651
645
  #... by presence
652
- it { should_have_sent_email.with_any_attachments }
646
+ it { is_expected.to have_sent_email.with_any_attachments }
653
647
 
654
648
  #... or by absence
655
- it { should_have_sent_email.with_no_attachments }
649
+ it { is_expected.to have_sent_email.with_no_attachments }
656
650
 
657
651
  end
658
652
  ```
659
653
 
660
- Core Extensions
661
- ---------------
662
-
663
- The mail gem adds several constants and methods to Ruby's core objects (similar to the activesupport gem from the Rails project). For example:
664
-
665
- NilClass::blank?
666
- NilClass::to_crlf
667
- NilClass::to_lf
668
- Object::blank?
669
- String::to_crlf
670
- String::to_lf
671
- String::blank?
672
- ...etc...
673
-
674
- For all the details, check out lib/mail/core_extensions/.
675
-
676
- Excerpts from TREC Spam Corpus 2005
677
- -----------------------------------
654
+ ## Excerpts from TREC Spam Corpus 2005
678
655
 
679
656
  The spec fixture files in spec/fixtures/emails/from_trec_2005 are from the
680
657
  2005 TREC Public Spam Corpus. They remain copyrighted under the terms of
@@ -692,8 +669,7 @@ They are used as allowed by 'Permitted Uses, Clause 3':
692
669
 
693
670
  -- http://plg.uwaterloo.ca/~gvcormac/treccorpus/
694
671
 
695
- License
696
- -------
672
+ ## License
697
673
 
698
674
  (The MIT License)
699
675
 
@@ -6,8 +6,8 @@ module Mail
6
6
  @parts_list = parts_list
7
7
  @content_disposition_type = 'attachment'
8
8
  parts_list.map { |p|
9
- if p.content_type == "message/rfc822"
10
- Mail.new(p.body).attachments
9
+ if p.mime_type == 'message/rfc822'
10
+ Mail.new(p.body.encoded).attachments
11
11
  elsif p.parts.empty?
12
12
  p if p.attachment?
13
13
  else
@@ -30,7 +30,7 @@ module Mail
30
30
  # mail.attachments['test.png'].filename #=> 'test.png'
31
31
  # mail.attachments[1].filename #=> 'test.jpg'
32
32
  def [](index_value)
33
- if index_value.is_a?(Fixnum)
33
+ if index_value.is_a?(Integer)
34
34
  self.fetch(index_value)
35
35
  else
36
36
  self.select { |a| a.filename == index_value }.first
@@ -44,6 +44,9 @@ module Mail
44
44
  :content_disposition => "#{@content_disposition_type}; filename=\"#{encoded_name}\"" }
45
45
 
46
46
  if value.is_a?(Hash)
47
+ if path = value.delete(:filename)
48
+ value[:content] ||= File.open(path, 'rb') { |f| f.read }
49
+ end
47
50
 
48
51
  default_values[:body] = value.delete(:content) if value[:content]
49
52
 
@@ -60,7 +63,7 @@ module Mail
60
63
 
61
64
  if value[:mime_type]
62
65
  default_values[:content_type] = value.delete(:mime_type)
63
- @mime_type = MIME::Types[default_values[:content_type]].first
66
+ @mime_type = MiniMime.lookup_by_content_type(default_values[:content_type])
64
67
  default_values[:content_transfer_encoding] ||= guess_encoding
65
68
  end
66
69
 
@@ -99,7 +102,8 @@ module Mail
99
102
  filename = filename.encode(Encoding::UTF_8) if filename.respond_to?(:encode)
100
103
  end
101
104
 
102
- @mime_type = MIME::Types.type_for(filename).first
105
+ @mime_type = MiniMime.lookup_by_filename(filename)
106
+ @mime_type && @mime_type.content_type
103
107
  end
104
108
 
105
109
  end
data/lib/mail/body.rb CHANGED
@@ -32,7 +32,7 @@ module Mail
32
32
  @preamble = nil
33
33
  @epilogue = nil
34
34
  @charset = nil
35
- @part_sort_order = [ "text/plain", "text/enriched", "text/html" ]
35
+ @part_sort_order = [ "text/plain", "text/enriched", "text/html", "multipart/alternative" ]
36
36
  @parts = Mail::PartsList.new
37
37
  if Utilities.blank?(string)
38
38
  @raw_source = ''
@@ -46,10 +46,10 @@ module Mail
46
46
  raise "You can only assign a string or an object that responds_to? :join or :to_s to a body."
47
47
  end
48
48
  end
49
- @encoding = (only_us_ascii? ? '7bit' : '8bit')
49
+ @encoding = default_encoding
50
50
  set_charset
51
51
  end
52
-
52
+
53
53
  # Matches this body with another body. Also matches the decoded value of this
54
54
  # body with a string.
55
55
  #
@@ -115,8 +115,8 @@ module Mail
115
115
  end
116
116
 
117
117
  # Allows you to set the sort order of the parts, overriding the default sort order.
118
- # Defaults to 'text/plain', then 'text/enriched', then 'text/html' with any other content
119
- # type coming after.
118
+ # Defaults to 'text/plain', then 'text/enriched', then 'text/html', then 'multipart/alternative'
119
+ # with any other content type coming after.
120
120
  def set_sort_order(order)
121
121
  @part_sort_order = order
122
122
  end
@@ -138,41 +138,39 @@ module Mail
138
138
  def raw_source
139
139
  @raw_source
140
140
  end
141
-
142
- def get_best_encoding(target)
143
- target_encoding = Mail::Encodings.get_encoding(target)
144
- target_encoding.get_best_compatible(encoding, raw_source)
141
+
142
+ def negotiate_best_encoding(message_encoding, allowed_encodings = nil)
143
+ Mail::Encodings::TransferEncoding.negotiate(message_encoding, encoding, raw_source, allowed_encodings)
145
144
  end
146
-
145
+
147
146
  # Returns a body encoded using transfer_encoding. Multipart always uses an
148
147
  # identiy encoding (i.e. no encoding).
149
148
  # Calling this directly is not a good idea, but supported for compatibility
150
149
  # TODO: Validate that preamble and epilogue are valid for requested encoding
151
- def encoded(transfer_encoding = '8bit')
150
+ def encoded(transfer_encoding = nil)
152
151
  if multipart?
153
152
  self.sort_parts!
154
153
  encoded_parts = parts.map { |p| p.encoded }
155
154
  ([preamble] + encoded_parts).join(crlf_boundary) + end_boundary + epilogue.to_s
156
155
  else
157
- be = get_best_encoding(transfer_encoding)
158
- dec = Mail::Encodings::get_encoding(encoding)
159
- enc = Mail::Encodings::get_encoding(be)
156
+ dec = Mail::Encodings.get_encoding(encoding)
157
+ enc = negotiate_best_encoding(transfer_encoding)
160
158
  if dec.nil?
161
- # Cannot decode, so skip normalization
162
- raw_source
159
+ # Cannot decode, so skip normalization
160
+ raw_source
163
161
  else
164
- # Decode then encode to normalize and allow transforming
165
- # from base64 to Q-P and vice versa
166
- decoded = dec.decode(raw_source)
167
- if defined?(Encoding) && charset && charset != "US-ASCII"
168
- decoded.encode!(charset)
169
- decoded.force_encoding('BINARY') unless Encoding.find(charset).ascii_compatible?
170
- end
171
- enc.encode(decoded)
162
+ # Decode then encode to normalize and allow transforming
163
+ # from base64 to Q-P and vice versa
164
+ decoded = dec.decode(raw_source)
165
+ if defined?(Encoding) && charset && charset != "US-ASCII"
166
+ decoded = decoded.encode(charset)
167
+ decoded.force_encoding('BINARY') unless Encoding.find(charset).ascii_compatible?
168
+ end
169
+ enc.encode(decoded)
172
170
  end
173
171
  end
174
172
  end
175
-
173
+
176
174
  def decoded
177
175
  if !Encodings.defined?(encoding)
178
176
  raise UnknownEncodingType, "Don't know how to decode #{encoding}, please call #encoded and decode it yourself."
@@ -200,13 +198,14 @@ module Mail
200
198
  @encoding
201
199
  end
202
200
  end
203
-
201
+
204
202
  def encoding=( val )
205
- @encoding = if val == "text" || Utilities.blank?(val)
206
- (only_us_ascii? ? '7bit' : '8bit')
207
- else
203
+ @encoding =
204
+ if val == "text" || Utilities.blank?(val)
205
+ default_encoding
206
+ else
208
207
  val
209
- end
208
+ end
210
209
  end
211
210
 
212
211
  # Returns the preamble (any text that is before the first MIME boundary)
@@ -268,14 +267,21 @@ module Mail
268
267
  self
269
268
  end
270
269
 
271
- def only_us_ascii?
272
- !(raw_source =~ /[^\x01-\x7f]/)
270
+ def ascii_only?
271
+ unless defined? @ascii_only
272
+ @ascii_only = raw_source.ascii_only?
273
+ end
274
+ @ascii_only
273
275
  end
274
-
276
+
275
277
  def empty?
276
278
  !!raw_source.to_s.empty?
277
279
  end
278
-
280
+
281
+ def default_encoding
282
+ ascii_only? ? '7bit' : '8bit'
283
+ end
284
+
279
285
  private
280
286
 
281
287
  # split parts by boundary, ignore first part if empty, append final part when closing boundary was missing
@@ -308,9 +314,9 @@ module Mail
308
314
  def end_boundary
309
315
  "\r\n--#{boundary}--\r\n"
310
316
  end
311
-
317
+
312
318
  def set_charset
313
- only_us_ascii? ? @charset = 'US-ASCII' : @charset = nil
319
+ @charset = ascii_only? ? 'US-ASCII' : nil
314
320
  end
315
321
  end
316
322
  end
@@ -1,21 +1,60 @@
1
1
  # frozen_string_literal: true
2
2
  module Mail
3
- module CheckDeliveryParams
4
- def check_delivery_params(mail)
5
- if Utilities.blank?(mail.smtp_envelope_from)
6
- raise ArgumentError.new('An SMTP From address is required to send a message. Set the message smtp_envelope_from, return_path, sender, or from address.')
3
+ module CheckDeliveryParams #:nodoc:
4
+ class << self
5
+ def check(mail)
6
+ [ check_from(mail.smtp_envelope_from),
7
+ check_to(mail.smtp_envelope_to),
8
+ check_message(mail) ]
7
9
  end
8
10
 
9
- if Utilities.blank?(mail.smtp_envelope_to)
10
- raise ArgumentError.new('An SMTP To address is required to send a message. Set the message smtp_envelope_to, to, cc, or bcc address.')
11
+ def check_from(addr)
12
+ if Utilities.blank?(addr)
13
+ raise ArgumentError, "SMTP From address may not be blank: #{addr.inspect}"
14
+ end
15
+
16
+ check_addr 'From', addr
17
+ end
18
+
19
+ def check_to(addrs)
20
+ if Utilities.blank?(addrs)
21
+ raise ArgumentError, "SMTP To address may not be blank: #{addrs.inspect}"
22
+ end
23
+
24
+ Array(addrs).map do |addr|
25
+ check_addr 'To', addr
26
+ end
11
27
  end
12
28
 
13
- message = mail.encoded if mail.respond_to?(:encoded)
14
- if Utilities.blank?(message)
15
- raise ArgumentError.new('An encoded message is required to send an email')
29
+ def check_addr(addr_name, addr)
30
+ validate_smtp_addr addr do |error_message|
31
+ raise ArgumentError, "SMTP #{addr_name} address #{error_message}: #{addr.inspect}"
32
+ end
16
33
  end
17
34
 
18
- [mail.smtp_envelope_from, mail.smtp_envelope_to, message]
35
+ def validate_smtp_addr(addr)
36
+ if addr
37
+ if addr.bytesize > 2048
38
+ yield 'may not exceed 2kB'
39
+ end
40
+
41
+ if /[\r\n]/ =~ addr
42
+ yield 'may not contain CR or LF line breaks'
43
+ end
44
+ end
45
+
46
+ addr
47
+ end
48
+
49
+ def check_message(message)
50
+ message = message.encoded if message.respond_to?(:encoded)
51
+
52
+ if Utilities.blank?(message)
53
+ raise ArgumentError, 'An encoded message is required to send an email'
54
+ end
55
+
56
+ message
57
+ end
19
58
  end
20
59
  end
21
60
  end
@@ -42,6 +42,8 @@ module Mail
42
42
  Mail::SMTPConnection
43
43
  when :test
44
44
  Mail::TestMailer
45
+ when :logger
46
+ Mail::LoggerDelivery
45
47
  else
46
48
  method
47
49
  end