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.
- checksums.yaml +4 -4
- data/README.md +74 -98
- data/lib/mail/attachments_list.rb +9 -5
- data/lib/mail/body.rb +42 -36
- data/lib/mail/check_delivery_params.rb +49 -10
- data/lib/mail/configuration.rb +2 -0
- data/lib/mail/core_extensions/smtp.rb +19 -16
- data/lib/mail/core_extensions/string.rb +0 -4
- data/lib/mail/elements/address.rb +37 -26
- data/lib/mail/elements/address_list.rb +10 -18
- data/lib/mail/elements/content_disposition_element.rb +8 -15
- data/lib/mail/elements/content_location_element.rb +5 -10
- data/lib/mail/elements/content_transfer_encoding_element.rb +5 -10
- data/lib/mail/elements/content_type_element.rb +8 -19
- data/lib/mail/elements/date_time_element.rb +6 -14
- data/lib/mail/elements/envelope_from_element.rb +14 -21
- data/lib/mail/elements/message_ids_element.rb +8 -12
- data/lib/mail/elements/mime_version_element.rb +6 -14
- data/lib/mail/elements/phrase_list.rb +6 -9
- data/lib/mail/elements/received_element.rb +9 -15
- data/lib/mail/encodings/7bit.rb +5 -15
- data/lib/mail/encodings/8bit.rb +2 -21
- data/lib/mail/encodings/base64.rb +11 -12
- data/lib/mail/encodings/binary.rb +3 -22
- data/lib/mail/encodings/identity.rb +24 -0
- data/lib/mail/encodings/quoted_printable.rb +6 -6
- data/lib/mail/encodings/transfer_encoding.rb +38 -29
- data/lib/mail/encodings/unix_to_unix.rb +2 -1
- data/lib/mail/encodings.rb +99 -43
- data/lib/mail/envelope.rb +1 -1
- data/lib/mail/field.rb +94 -59
- data/lib/mail/fields/bcc_field.rb +2 -2
- data/lib/mail/fields/cc_field.rb +1 -1
- data/lib/mail/fields/comments_field.rb +1 -1
- data/lib/mail/fields/common/address_container.rb +2 -2
- data/lib/mail/fields/common/common_address.rb +32 -7
- data/lib/mail/fields/common/common_field.rb +1 -10
- data/lib/mail/fields/common/parameter_hash.rb +1 -1
- data/lib/mail/fields/content_description_field.rb +1 -1
- data/lib/mail/fields/content_disposition_field.rb +3 -3
- data/lib/mail/fields/content_id_field.rb +2 -2
- data/lib/mail/fields/content_location_field.rb +1 -1
- data/lib/mail/fields/content_transfer_encoding_field.rb +1 -1
- data/lib/mail/fields/content_type_field.rb +3 -8
- data/lib/mail/fields/date_field.rb +2 -3
- data/lib/mail/fields/from_field.rb +1 -1
- data/lib/mail/fields/in_reply_to_field.rb +1 -1
- data/lib/mail/fields/keywords_field.rb +1 -1
- data/lib/mail/fields/message_id_field.rb +1 -1
- data/lib/mail/fields/mime_version_field.rb +1 -1
- data/lib/mail/fields/optional_field.rb +4 -1
- data/lib/mail/fields/received_field.rb +1 -1
- data/lib/mail/fields/references_field.rb +1 -1
- data/lib/mail/fields/reply_to_field.rb +1 -1
- data/lib/mail/fields/resent_bcc_field.rb +1 -1
- data/lib/mail/fields/resent_cc_field.rb +1 -1
- data/lib/mail/fields/resent_date_field.rb +0 -1
- data/lib/mail/fields/resent_from_field.rb +1 -1
- data/lib/mail/fields/resent_message_id_field.rb +1 -1
- data/lib/mail/fields/resent_sender_field.rb +1 -1
- data/lib/mail/fields/resent_to_field.rb +1 -1
- data/lib/mail/fields/return_path_field.rb +1 -1
- data/lib/mail/fields/sender_field.rb +1 -1
- data/lib/mail/fields/subject_field.rb +1 -1
- data/lib/mail/fields/to_field.rb +1 -1
- data/lib/mail/fields/unstructured_field.rb +21 -4
- data/lib/mail/header.rb +10 -8
- data/lib/mail/mail.rb +2 -10
- data/lib/mail/matchers/has_sent_mail.rb +21 -1
- data/lib/mail/message.rb +77 -66
- data/lib/mail/multibyte/chars.rb +31 -30
- data/lib/mail/multibyte.rb +64 -15
- data/lib/mail/network/delivery_methods/exim.rb +6 -10
- data/lib/mail/network/delivery_methods/file_delivery.rb +4 -8
- data/lib/mail/network/delivery_methods/logger_delivery.rb +37 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +16 -11
- data/lib/mail/network/delivery_methods/smtp.rb +59 -53
- data/lib/mail/network/delivery_methods/smtp_connection.rb +10 -6
- data/lib/mail/network/delivery_methods/test_mailer.rb +5 -8
- data/lib/mail/network/retriever_methods/imap.rb +18 -5
- data/lib/mail/network/retriever_methods/pop3.rb +3 -1
- data/lib/mail/network/retriever_methods/test_retriever.rb +1 -1
- data/lib/mail/network.rb +1 -0
- data/lib/mail/parser_tools.rb +15 -0
- data/lib/mail/parsers/address_lists_parser.rb +33186 -112
- data/lib/mail/parsers/address_lists_parser.rl +172 -0
- data/lib/mail/parsers/content_disposition_parser.rb +888 -55
- data/lib/mail/parsers/content_disposition_parser.rl +82 -0
- data/lib/mail/parsers/content_location_parser.rb +800 -23
- data/lib/mail/parsers/content_location_parser.rl +71 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +510 -22
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +64 -0
- data/lib/mail/parsers/content_type_parser.rb +1032 -54
- data/lib/mail/parsers/content_type_parser.rl +83 -0
- data/lib/mail/parsers/date_time_parser.rb +873 -26
- data/lib/mail/parsers/date_time_parser.rl +62 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3564 -36
- data/lib/mail/parsers/envelope_from_parser.rl +82 -0
- data/lib/mail/parsers/message_ids_parser.rb +2843 -25
- data/lib/mail/parsers/message_ids_parser.rl +82 -0
- data/lib/mail/parsers/mime_version_parser.rb +493 -26
- data/lib/mail/parsers/mime_version_parser.rl +61 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +874 -19
- data/lib/mail/parsers/phrase_lists_parser.rl +83 -0
- data/lib/mail/parsers/received_parser.rb +8743 -38
- data/lib/mail/parsers/received_parser.rl +84 -0
- data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
- data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
- data/lib/mail/parsers/rfc2045_mime.rl +16 -0
- data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
- data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
- data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
- data/lib/mail/parsers/rfc5322.rl +59 -0
- data/lib/mail/parsers/rfc5322_address.rl +72 -0
- data/lib/mail/parsers/{ragel/date_time.rl → rfc5322_date_time.rl} +8 -1
- data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
- data/lib/mail/parsers.rb +16 -24
- data/lib/mail/part.rb +1 -1
- data/lib/mail/parts_list.rb +5 -6
- data/lib/mail/utilities.rb +63 -18
- data/lib/mail/version.rb +2 -2
- data/lib/mail/version_specific/ruby_1_8.rb +40 -3
- data/lib/mail/version_specific/ruby_1_9.rb +64 -9
- data/lib/mail.rb +3 -16
- metadata +30 -53
- data/CHANGELOG.rdoc +0 -787
- data/CONTRIBUTING.md +0 -60
- data/Dependencies.txt +0 -2
- data/Gemfile +0 -11
- data/Rakefile +0 -29
- data/TODO.rdoc +0 -9
- data/lib/mail/core_extensions/string/access.rb +0 -146
- data/lib/mail/core_extensions/string/multibyte.rb +0 -79
- data/lib/mail/multibyte/exceptions.rb +0 -9
- data/lib/mail/parsers/ragel/common.rl +0 -185
- data/lib/mail/parsers/ragel/parser_info.rb +0 -61
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +0 -14864
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +0 -751
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +0 -614
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +0 -447
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +0 -825
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +0 -817
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +0 -2149
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +0 -1570
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +0 -440
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +0 -564
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +0 -51
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +0 -5144
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +0 -37
- data/lib/mail/parsers/ragel/ruby.rb +0 -40
- data/lib/mail/parsers/ragel.rb +0 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0f77ef2d4e2ecc02b59f5431cd56e3c0a5569262
|
|
4
|
+
data.tar.gz: a6e4a0ee6b7d2d1a824578a43a5c73893ae3fa10
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 70f3d73bb71de6e3d6121df0e93cd3909fb35eef6716c0597803a67ee341445385951dc662901dce2e806840c399d1f6ea0015987b2944b9fb24f9973a8e97af
|
|
7
|
+
data.tar.gz: 0d7283e6e57f4600704b9d9e45ae17e77e8105db42a394174217c7f488e81ac4598fef6492e85e24a8e763ceb302ee3ee6754fa1bf3bf9777bfa37a707157d4b
|
data/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
Mail [](https://travis-ci.org/mikel/mail)
|
|
2
|
-
====
|
|
1
|
+
# Mail [](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
|
-
|
|
55
|
+
Mail supports Ruby 1.8.7+, including JRuby and Rubinius.
|
|
46
56
|
|
|
47
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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 & 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
|
|
79
|
-
* Auto encoding of non US-ASCII bodies
|
|
72
|
+
* Auto-encoding of non-US-ASCII bodies and header fields
|
|
80
73
|
|
|
81
|
-
Mail is
|
|
82
|
-
emails.
|
|
83
|
-
it also is quite robust, meaning, if it finds something
|
|
84
|
-
not crash, instead, it will skip the problem and keep
|
|
85
|
-
it doesn't understand, it will initialise the header
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
|
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.
|
|
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
|
|
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,
|
|
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
|
|
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 {
|
|
608
|
+
it { is_expected.to have_sent_email } # passes if any email at all was sent
|
|
615
609
|
|
|
616
|
-
it {
|
|
617
|
-
it {
|
|
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 {
|
|
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 {
|
|
617
|
+
it { is_expected.to have_sent_email.to('mike1@me.com').to('mike2@me.com') }
|
|
624
618
|
|
|
625
|
-
it {
|
|
619
|
+
it { is_expected.to have_sent_email.with_subject('testing') }
|
|
626
620
|
|
|
627
|
-
it {
|
|
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 {
|
|
633
|
-
it {
|
|
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 {
|
|
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 {
|
|
637
|
+
it { is_expected.to have_sent_email.with_attachments(my_attachment) }
|
|
644
638
|
|
|
645
639
|
# ... or any attachment
|
|
646
|
-
it {
|
|
640
|
+
it { is_expected.to have_sent_email.with_attachments(any_attachment) }
|
|
647
641
|
|
|
648
642
|
# ... by array of attachments
|
|
649
|
-
it {
|
|
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 {
|
|
646
|
+
it { is_expected.to have_sent_email.with_any_attachments }
|
|
653
647
|
|
|
654
648
|
#... or by absence
|
|
655
|
-
it {
|
|
649
|
+
it { is_expected.to have_sent_email.with_no_attachments }
|
|
656
650
|
|
|
657
651
|
end
|
|
658
652
|
```
|
|
659
653
|
|
|
660
|
-
|
|
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.
|
|
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?(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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'
|
|
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
|
|
143
|
-
|
|
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 =
|
|
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
|
-
|
|
158
|
-
|
|
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
|
-
|
|
162
|
-
|
|
159
|
+
# Cannot decode, so skip normalization
|
|
160
|
+
raw_source
|
|
163
161
|
else
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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 =
|
|
206
|
-
|
|
207
|
-
|
|
203
|
+
@encoding =
|
|
204
|
+
if val == "text" || Utilities.blank?(val)
|
|
205
|
+
default_encoding
|
|
206
|
+
else
|
|
208
207
|
val
|
|
209
|
-
|
|
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
|
|
272
|
-
|
|
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
|
-
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
10
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
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
|