mail 2.6.1 → 2.7.1
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 +5 -5
- data/MIT-LICENSE +1 -1
- data/README.md +92 -80
- data/lib/mail/attachments_list.rb +11 -5
- data/lib/mail/body.rb +81 -44
- data/lib/mail/check_delivery_params.rb +50 -10
- data/lib/mail/configuration.rb +3 -0
- data/lib/mail/{patterns.rb → constants.rb} +26 -6
- data/lib/mail/core_extensions/smtp.rb +20 -16
- data/lib/mail/core_extensions/string.rb +1 -27
- data/lib/mail/elements/address.rb +81 -93
- data/lib/mail/elements/address_list.rb +12 -29
- data/lib/mail/elements/content_disposition_element.rb +9 -15
- data/lib/mail/elements/content_location_element.rb +8 -12
- data/lib/mail/elements/content_transfer_encoding_element.rb +6 -10
- data/lib/mail/elements/content_type_element.rb +9 -19
- data/lib/mail/elements/date_time_element.rb +7 -14
- data/lib/mail/elements/envelope_from_element.rb +15 -21
- data/lib/mail/elements/message_ids_element.rb +12 -14
- data/lib/mail/elements/mime_version_element.rb +7 -14
- data/lib/mail/elements/phrase_list.rb +7 -9
- data/lib/mail/elements/received_element.rb +10 -15
- data/lib/mail/elements.rb +1 -0
- data/lib/mail/encodings/7bit.rb +6 -15
- data/lib/mail/encodings/8bit.rb +5 -18
- data/lib/mail/encodings/base64.rb +15 -10
- data/lib/mail/encodings/binary.rb +4 -22
- data/lib/mail/encodings/identity.rb +24 -0
- data/lib/mail/encodings/quoted_printable.rb +13 -7
- data/lib/mail/encodings/transfer_encoding.rb +47 -28
- data/lib/mail/encodings/unix_to_unix.rb +20 -0
- data/lib/mail/encodings.rb +121 -82
- data/lib/mail/envelope.rb +2 -1
- data/lib/mail/field.rb +114 -62
- data/lib/mail/field_list.rb +2 -1
- data/lib/mail/fields/bcc_field.rb +17 -5
- data/lib/mail/fields/cc_field.rb +2 -2
- data/lib/mail/fields/comments_field.rb +2 -1
- data/lib/mail/fields/common/address_container.rb +3 -2
- data/lib/mail/fields/common/common_address.rb +40 -14
- data/lib/mail/fields/common/common_date.rb +2 -1
- data/lib/mail/fields/common/common_field.rb +6 -11
- data/lib/mail/fields/common/common_message_id.rb +3 -2
- data/lib/mail/fields/common/parameter_hash.rb +5 -4
- data/lib/mail/fields/content_description_field.rb +2 -1
- data/lib/mail/fields/content_disposition_field.rb +14 -13
- data/lib/mail/fields/content_id_field.rb +5 -4
- data/lib/mail/fields/content_location_field.rb +3 -2
- data/lib/mail/fields/content_transfer_encoding_field.rb +3 -2
- data/lib/mail/fields/content_type_field.rb +7 -11
- data/lib/mail/fields/date_field.rb +4 -4
- data/lib/mail/fields/from_field.rb +2 -2
- data/lib/mail/fields/in_reply_to_field.rb +2 -1
- data/lib/mail/fields/keywords_field.rb +3 -3
- data/lib/mail/fields/message_id_field.rb +3 -2
- data/lib/mail/fields/mime_version_field.rb +4 -3
- data/lib/mail/fields/optional_field.rb +5 -1
- data/lib/mail/fields/received_field.rb +5 -4
- data/lib/mail/fields/references_field.rb +2 -1
- data/lib/mail/fields/reply_to_field.rb +2 -2
- data/lib/mail/fields/resent_bcc_field.rb +2 -2
- data/lib/mail/fields/resent_cc_field.rb +2 -2
- data/lib/mail/fields/resent_date_field.rb +2 -2
- data/lib/mail/fields/resent_from_field.rb +2 -2
- data/lib/mail/fields/resent_message_id_field.rb +2 -1
- data/lib/mail/fields/resent_sender_field.rb +2 -2
- data/lib/mail/fields/resent_to_field.rb +2 -2
- data/lib/mail/fields/return_path_field.rb +2 -2
- data/lib/mail/fields/sender_field.rb +2 -2
- data/lib/mail/fields/structured_field.rb +1 -0
- data/lib/mail/fields/subject_field.rb +2 -1
- data/lib/mail/fields/to_field.rb +2 -2
- data/lib/mail/fields/unstructured_field.rb +28 -10
- data/lib/mail/fields.rb +1 -0
- data/lib/mail/header.rb +18 -14
- data/lib/mail/indifferent_hash.rb +1 -0
- data/lib/mail/mail.rb +6 -11
- data/lib/mail/matchers/attachment_matchers.rb +29 -0
- data/lib/mail/matchers/has_sent_mail.rb +53 -9
- data/lib/mail/message.rb +99 -89
- data/lib/mail/multibyte/chars.rb +32 -30
- data/lib/mail/multibyte/unicode.rb +31 -26
- data/lib/mail/multibyte/utils.rb +1 -0
- data/lib/mail/multibyte.rb +65 -15
- data/lib/mail/network/delivery_methods/exim.rb +7 -10
- data/lib/mail/network/delivery_methods/file_delivery.rb +5 -8
- data/lib/mail/network/delivery_methods/logger_delivery.rb +37 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +17 -11
- data/lib/mail/network/delivery_methods/smtp.rb +60 -53
- data/lib/mail/network/delivery_methods/smtp_connection.rb +11 -6
- data/lib/mail/network/delivery_methods/test_mailer.rb +6 -8
- data/lib/mail/network/retriever_methods/base.rb +1 -0
- data/lib/mail/network/retriever_methods/imap.rb +19 -5
- data/lib/mail/network/retriever_methods/pop3.rb +4 -1
- data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
- data/lib/mail/network.rb +2 -0
- data/lib/mail/parser_tools.rb +15 -0
- data/lib/mail/parsers/address_lists_parser.rb +33208 -104
- data/lib/mail/parsers/address_lists_parser.rl +172 -0
- data/lib/mail/parsers/content_disposition_parser.rb +877 -49
- data/lib/mail/parsers/content_disposition_parser.rl +82 -0
- data/lib/mail/parsers/content_location_parser.rb +804 -23
- data/lib/mail/parsers/content_location_parser.rl +71 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +502 -19
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +64 -0
- data/lib/mail/parsers/content_type_parser.rb +1024 -46
- data/lib/mail/parsers/content_type_parser.rl +83 -0
- data/lib/mail/parsers/date_time_parser.rb +872 -23
- data/lib/mail/parsers/date_time_parser.rl +62 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3570 -34
- data/lib/mail/parsers/envelope_from_parser.rl +82 -0
- data/lib/mail/parsers/message_ids_parser.rb +2840 -25
- data/lib/mail/parsers/message_ids_parser.rl +82 -0
- data/lib/mail/parsers/mime_version_parser.rb +492 -26
- data/lib/mail/parsers/mime_version_parser.rl +61 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +862 -17
- data/lib/mail/parsers/phrase_lists_parser.rl +83 -0
- data/lib/mail/parsers/received_parser.rb +8765 -36
- 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 +17 -24
- data/lib/mail/part.rb +8 -5
- data/lib/mail/parts_list.rb +31 -14
- data/lib/mail/utilities.rb +112 -13
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version.rb +8 -15
- data/lib/mail/version_specific/ruby_1_8.rb +52 -8
- data/lib/mail/version_specific/ruby_1_9.rb +143 -24
- data/lib/mail.rb +8 -14
- metadata +71 -81
- data/CHANGELOG.rdoc +0 -752
- data/CONTRIBUTING.md +0 -60
- data/Dependencies.txt +0 -2
- data/Gemfile +0 -15
- data/Rakefile +0 -29
- data/TODO.rdoc +0 -9
- data/VERSION +0 -4
- data/lib/mail/core_extensions/nil.rb +0 -19
- data/lib/mail/core_extensions/object.rb +0 -13
- data/lib/mail/core_extensions/string/access.rb +0 -145
- data/lib/mail/core_extensions/string/multibyte.rb +0 -78
- data/lib/mail/multibyte/exceptions.rb +0 -8
- data/lib/mail/parsers/ragel/common.rl +0 -184
- 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 -2129
- 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 -39
- data/lib/mail/parsers/ragel.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2e806bc9b7c6c6df8de9c9dc80b4cf3a099bad3153f568d0ee4d9287cd34a014
|
4
|
+
data.tar.gz: 182ed03957858cce70691eb79543f13d53e4ddf43684bf50bc011e904d3a84ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c42702e6529565ae63c486fef492b89a19eb394fb6fe5aaf004862257ef3d840579a3cabb95dd2075ddbc617e077110684d8f47052e51d0435b94ef4a2373c3
|
7
|
+
data.tar.gz: 31278e7d48271cfec8541d1094fedd1cc62578a6d9f18e0eafd09ebcac4e5edf3e78a3b902aca3e97d7416d37b0f0c07ba2dde2f5462d6317058552bbc0dbfe7
|
data/MIT-LICENSE
CHANGED
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.
|
@@ -15,7 +13,7 @@ Built from my experience with TMail, it is designed to be a pure ruby
|
|
15
13
|
implementation that makes generating, sending and parsing emails a no
|
16
14
|
brainer.
|
17
15
|
|
18
|
-
It is also designed
|
16
|
+
It is also designed from the ground up to work with the more modern versions
|
19
17
|
of Ruby. This is because Ruby > 1.9 handles text encodings much more wonderfully
|
20
18
|
than Ruby 1.8.x and so these features have been taken full advantage of in this
|
21
19
|
library allowing Mail to handle a lot more messages more cleanly than TMail.
|
@@ -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-p320 [ x86_64 ]
|
49
|
-
* ruby-1.9.3-p327 [ x86_64 ]
|
50
|
-
* ruby-2.0.0-p451 [ 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
|
@@ -110,23 +101,22 @@ the gem gets released.
|
|
110
101
|
|
111
102
|
It also means you can be sure Mail will behave correctly.
|
112
103
|
|
113
|
-
|
114
|
-
|
104
|
+
Note: If you care about core extensions (aka "monkey-patching"), please read the Core Extensions section near the end of this README.
|
105
|
+
|
106
|
+
## API Policy
|
115
107
|
|
116
108
|
No API removals within a single point release. All removals to be deprecated with
|
117
109
|
warnings for at least one MINOR point release before removal.
|
118
110
|
|
119
111
|
Also, all private or protected methods to be declared as such - though this is still I/P.
|
120
112
|
|
121
|
-
Installation
|
122
|
-
------------
|
113
|
+
## Installation
|
123
114
|
|
124
115
|
Installation is fairly simple, I host mail on rubygems, so you can just do:
|
125
116
|
|
126
117
|
# gem install mail
|
127
118
|
|
128
|
-
Encodings
|
129
|
-
---------
|
119
|
+
## Encodings
|
130
120
|
|
131
121
|
If you didn't know, handling encodings in Emails is not as straight forward as you
|
132
122
|
would hope.
|
@@ -158,13 +148,11 @@ I have tried to simplify it some:
|
|
158
148
|
provide encoded parameter values when you call the parameter names through the
|
159
149
|
<code>object.parameters['<parameter_name>']</code> method call.
|
160
150
|
|
161
|
-
Contributing
|
162
|
-
------------
|
151
|
+
## Contributing
|
163
152
|
|
164
153
|
Please do! Contributing is easy in Mail. Please read the CONTRIBUTING.md document for more info
|
165
154
|
|
166
|
-
Usage
|
167
|
-
-----
|
155
|
+
## Usage
|
168
156
|
|
169
157
|
All major mail functions should be able to happen from the Mail module.
|
170
158
|
So, you should be able to just <code>require 'mail'</code> to get started.
|
@@ -232,7 +220,7 @@ what you are doing.
|
|
232
220
|
### Sending an email:
|
233
221
|
|
234
222
|
Mail defaults to sending via SMTP to local host port 25. If you have a
|
235
|
-
sendmail or postfix daemon running on
|
223
|
+
sendmail or postfix daemon running on this port, sending email is as
|
236
224
|
easy as:
|
237
225
|
|
238
226
|
```ruby
|
@@ -292,7 +280,17 @@ mail.delivery_method :exim, :location => "/usr/bin/exim"
|
|
292
280
|
mail.deliver
|
293
281
|
```
|
294
282
|
|
295
|
-
|
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:
|
296
294
|
|
297
295
|
You can configure Mail to receive email using <code>retriever_method</code>
|
298
296
|
within <code>Mail.defaults</code>:
|
@@ -345,7 +343,7 @@ mail.cc #=> 'sam@test.lindsaar.net'
|
|
345
343
|
mail.subject #=> "This is the subject"
|
346
344
|
mail.date.to_s #=> '21 Nov 1997 09:55:06 -0600'
|
347
345
|
mail.message_id #=> '<4D6AA7EB.6490534@xxx.xxx>'
|
348
|
-
mail.
|
346
|
+
mail.decoded #=> 'This is the body of the email...
|
349
347
|
```
|
350
348
|
|
351
349
|
Many more methods available.
|
@@ -371,7 +369,7 @@ is another message which can have many or no parts.
|
|
371
369
|
A message will only have parts if it is a multipart/mixed or multipart/related
|
372
370
|
content type and has a boundary defined.
|
373
371
|
|
374
|
-
### Testing and
|
372
|
+
### Testing and Extracting Attachments
|
375
373
|
```ruby
|
376
374
|
mail.attachments.each do | attachment |
|
377
375
|
# Attachments is an AttachmentsList object containing a
|
@@ -380,14 +378,14 @@ mail.attachments.each do | attachment |
|
|
380
378
|
# extracting images for example...
|
381
379
|
filename = attachment.filename
|
382
380
|
begin
|
383
|
-
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}
|
384
382
|
rescue => e
|
385
383
|
puts "Unable to save data for #{filename} because #{e.message}"
|
386
384
|
end
|
387
385
|
end
|
388
386
|
end
|
389
387
|
```
|
390
|
-
### Writing and
|
388
|
+
### Writing and Sending a Multipart/Alternative (HTML and Text) Email
|
391
389
|
|
392
390
|
Mail makes some basic assumptions and makes doing the common thing as
|
393
391
|
simple as possible.... (asking a lot from a mail library)
|
@@ -453,7 +451,7 @@ Mail assumes that if your text in the body is only us-ascii, that your
|
|
453
451
|
transfer encoding is 7bit and it is text/plain. You can override this
|
454
452
|
by explicitly declaring it.
|
455
453
|
|
456
|
-
### Making Multipart/Alternate,
|
454
|
+
### Making Multipart/Alternate, Without a Block
|
457
455
|
|
458
456
|
You don't have to use a block with the text and html part included, you
|
459
457
|
can just do it declaratively. However, you need to add Mail::Parts to
|
@@ -481,7 +479,7 @@ mail.html_part = html_part
|
|
481
479
|
|
482
480
|
Results in the same email as done using the block form
|
483
481
|
|
484
|
-
### Getting
|
482
|
+
### Getting Error Reports from an Email:
|
485
483
|
|
486
484
|
```ruby
|
487
485
|
@mail = Mail.read('/path/to/bounce_message.eml')
|
@@ -525,7 +523,6 @@ than mail (this should be rarely needed)
|
|
525
523
|
|
526
524
|
```ruby
|
527
525
|
@mail = Mail.new
|
528
|
-
file_data = File.read('path/to/myfile.pdf')
|
529
526
|
@mail.attachments['myfile.pdf'] = { :mime_type => 'application/x-pdf',
|
530
527
|
:content => File.read('path/to/myfile.pdf') }
|
531
528
|
@mail.parts.first.mime_type #=> 'application/x-pdf'
|
@@ -558,8 +555,7 @@ end
|
|
558
555
|
```
|
559
556
|
See "Testing and extracting attachments" above for more details.
|
560
557
|
|
561
|
-
Using Mail with Testing or Spec'ing Libraries
|
562
|
-
---------------------------------------------
|
558
|
+
## Using Mail with Testing or Spec'ing Libraries
|
563
559
|
|
564
560
|
If mail is part of your system, you'll need a way to test it without actually
|
565
561
|
sending emails, the TestMailer can do this for you.
|
@@ -588,7 +584,7 @@ Mail::TestMailer.deliveries.clear
|
|
588
584
|
=> []
|
589
585
|
```
|
590
586
|
|
591
|
-
There is also a set of RSpec matchers stolen
|
587
|
+
There is also a set of RSpec matchers stolen/inspired by Shoulda's ActionMailer matchers (you'll want to set <code>delivery_method</code> as above too):
|
592
588
|
|
593
589
|
```ruby
|
594
590
|
Mail.defaults do
|
@@ -609,36 +605,53 @@ describe "sending an email" do
|
|
609
605
|
end
|
610
606
|
end
|
611
607
|
|
612
|
-
it {
|
608
|
+
it { is_expected.to have_sent_email } # passes if any email at all was sent
|
613
609
|
|
614
|
-
it {
|
615
|
-
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') }
|
616
612
|
|
617
613
|
# can specify a list of recipients...
|
618
|
-
it {
|
614
|
+
it { is_expected.to have_sent_email.to(['mike1@me.com', 'mike2@me.com']) }
|
619
615
|
|
620
616
|
# ...or chain recipients together
|
621
|
-
it {
|
617
|
+
it { is_expected.to have_sent_email.to('mike1@me.com').to('mike2@me.com') }
|
622
618
|
|
623
|
-
it {
|
619
|
+
it { is_expected.to have_sent_email.with_subject('testing') }
|
624
620
|
|
625
|
-
it {
|
621
|
+
it { is_expected.to have_sent_email.with_body('hello') }
|
626
622
|
|
627
623
|
# Can match subject or body with a regex
|
628
624
|
# (or anything that responds_to? :match)
|
629
625
|
|
630
|
-
it {
|
631
|
-
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/) }
|
632
628
|
|
633
629
|
# Can chain together modifiers
|
634
630
|
# Note that apart from recipients, repeating a modifier overwrites old value.
|
635
631
|
|
636
|
-
it {
|
632
|
+
it { is_expected.to have_sent_email.from('you@you.com').to('mike1@me.com').matching_body(/hell/)
|
633
|
+
|
634
|
+
# test for attachments
|
635
|
+
|
636
|
+
# ... by specific attachment
|
637
|
+
it { is_expected.to have_sent_email.with_attachments(my_attachment) }
|
638
|
+
|
639
|
+
# ... or any attachment
|
640
|
+
it { is_expected.to have_sent_email.with_attachments(any_attachment) }
|
641
|
+
|
642
|
+
# ... by array of attachments
|
643
|
+
it { is_expected.to have_sent_email.with_attachments([my_attachment1, my_attachment2]) } #note that order is important
|
644
|
+
|
645
|
+
#... by presence
|
646
|
+
it { is_expected.to have_sent_email.with_any_attachments }
|
647
|
+
|
648
|
+
#... or by absence
|
649
|
+
it { is_expected.to have_sent_email.with_no_attachments }
|
650
|
+
|
637
651
|
end
|
638
652
|
```
|
639
653
|
|
640
|
-
Excerpts from TREC Spam Corpus 2005
|
641
|
-
-----------------------------------
|
654
|
+
## Excerpts from TREC Spam Corpus 2005
|
642
655
|
|
643
656
|
The spec fixture files in spec/fixtures/emails/from_trec_2005 are from the
|
644
657
|
2005 TREC Public Spam Corpus. They remain copyrighted under the terms of
|
@@ -656,12 +669,11 @@ They are used as allowed by 'Permitted Uses, Clause 3':
|
|
656
669
|
|
657
670
|
-- http://plg.uwaterloo.ca/~gvcormac/treccorpus/
|
658
671
|
|
659
|
-
License
|
660
|
-
-------
|
672
|
+
## License
|
661
673
|
|
662
674
|
(The MIT License)
|
663
675
|
|
664
|
-
Copyright (c) 2009-
|
676
|
+
Copyright (c) 2009-2016 Mikel Lindsaar
|
665
677
|
|
666
678
|
Permission is hereby granted, free of charge, to any person obtaining
|
667
679
|
a copy of this software and associated documentation files (the
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Mail
|
2
3
|
class AttachmentsList < Array
|
3
4
|
|
@@ -5,8 +6,8 @@ module Mail
|
|
5
6
|
@parts_list = parts_list
|
6
7
|
@content_disposition_type = 'attachment'
|
7
8
|
parts_list.map { |p|
|
8
|
-
if p.
|
9
|
-
Mail.new(p.body).attachments
|
9
|
+
if p.mime_type == 'message/rfc822'
|
10
|
+
Mail.new(p.body.encoded).attachments
|
10
11
|
elsif p.parts.empty?
|
11
12
|
p if p.attachment?
|
12
13
|
else
|
@@ -29,7 +30,7 @@ module Mail
|
|
29
30
|
# mail.attachments['test.png'].filename #=> 'test.png'
|
30
31
|
# mail.attachments[1].filename #=> 'test.jpg'
|
31
32
|
def [](index_value)
|
32
|
-
if index_value.is_a?(
|
33
|
+
if index_value.is_a?(Integer)
|
33
34
|
self.fetch(index_value)
|
34
35
|
else
|
35
36
|
self.select { |a| a.filename == index_value }.first
|
@@ -43,6 +44,9 @@ module Mail
|
|
43
44
|
:content_disposition => "#{@content_disposition_type}; filename=\"#{encoded_name}\"" }
|
44
45
|
|
45
46
|
if value.is_a?(Hash)
|
47
|
+
if path = value.delete(:filename)
|
48
|
+
value[:content] ||= File.open(path, 'rb') { |f| f.read }
|
49
|
+
end
|
46
50
|
|
47
51
|
default_values[:body] = value.delete(:content) if value[:content]
|
48
52
|
|
@@ -59,7 +63,7 @@ module Mail
|
|
59
63
|
|
60
64
|
if value[:mime_type]
|
61
65
|
default_values[:content_type] = value.delete(:mime_type)
|
62
|
-
@mime_type =
|
66
|
+
@mime_type = MiniMime.lookup_by_content_type(default_values[:content_type])
|
63
67
|
default_values[:content_transfer_encoding] ||= guess_encoding
|
64
68
|
end
|
65
69
|
|
@@ -71,6 +75,7 @@ module Mail
|
|
71
75
|
|
72
76
|
if hash[:body].respond_to? :force_encoding and hash[:body].respond_to? :valid_encoding?
|
73
77
|
if not hash[:body].valid_encoding? and default_values[:content_transfer_encoding].downcase == "binary"
|
78
|
+
hash[:body] = hash[:body].dup if hash[:body].frozen?
|
74
79
|
hash[:body].force_encoding("BINARY")
|
75
80
|
end
|
76
81
|
end
|
@@ -97,7 +102,8 @@ module Mail
|
|
97
102
|
filename = filename.encode(Encoding::UTF_8) if filename.respond_to?(:encode)
|
98
103
|
end
|
99
104
|
|
100
|
-
@mime_type =
|
105
|
+
@mime_type = MiniMime.lookup_by_filename(filename)
|
106
|
+
@mime_type && @mime_type.content_type
|
101
107
|
end
|
102
108
|
|
103
109
|
end
|
data/lib/mail/body.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
module Mail
|
3
4
|
|
4
5
|
# = Body
|
@@ -31,24 +32,24 @@ module Mail
|
|
31
32
|
@preamble = nil
|
32
33
|
@epilogue = nil
|
33
34
|
@charset = nil
|
34
|
-
@part_sort_order = [ "text/plain", "text/enriched", "text/html" ]
|
35
|
+
@part_sort_order = [ "text/plain", "text/enriched", "text/html", "multipart/alternative" ]
|
35
36
|
@parts = Mail::PartsList.new
|
36
|
-
if
|
37
|
+
if Utilities.blank?(string)
|
37
38
|
@raw_source = ''
|
38
39
|
else
|
39
40
|
# Do join first incase we have been given an Array in Ruby 1.9
|
40
41
|
if string.respond_to?(:join)
|
41
|
-
@raw_source = string.join('')
|
42
|
+
@raw_source = ::Mail::Utilities.to_crlf(string.join(''))
|
42
43
|
elsif string.respond_to?(:to_s)
|
43
|
-
@raw_source = string.to_s
|
44
|
+
@raw_source = ::Mail::Utilities.to_crlf(string.to_s)
|
44
45
|
else
|
45
46
|
raise "You can only assign a string or an object that responds_to? :join or :to_s to a body."
|
46
47
|
end
|
47
48
|
end
|
48
|
-
@encoding =
|
49
|
+
@encoding = default_encoding
|
49
50
|
set_charset
|
50
51
|
end
|
51
|
-
|
52
|
+
|
52
53
|
# Matches this body with another body. Also matches the decoded value of this
|
53
54
|
# body with a string.
|
54
55
|
#
|
@@ -114,8 +115,8 @@ module Mail
|
|
114
115
|
end
|
115
116
|
|
116
117
|
# Allows you to set the sort order of the parts, overriding the default sort order.
|
117
|
-
# Defaults to 'text/plain', then 'text/enriched', then 'text/html'
|
118
|
-
# 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.
|
119
120
|
def set_sort_order(order)
|
120
121
|
@part_sort_order = order
|
121
122
|
end
|
@@ -137,41 +138,45 @@ module Mail
|
|
137
138
|
def raw_source
|
138
139
|
@raw_source
|
139
140
|
end
|
140
|
-
|
141
|
-
def
|
142
|
-
|
143
|
-
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)
|
144
144
|
end
|
145
|
-
|
145
|
+
|
146
146
|
# Returns a body encoded using transfer_encoding. Multipart always uses an
|
147
147
|
# identiy encoding (i.e. no encoding).
|
148
148
|
# Calling this directly is not a good idea, but supported for compatibility
|
149
149
|
# TODO: Validate that preamble and epilogue are valid for requested encoding
|
150
|
-
def encoded(transfer_encoding =
|
150
|
+
def encoded(transfer_encoding = nil)
|
151
151
|
if multipart?
|
152
152
|
self.sort_parts!
|
153
153
|
encoded_parts = parts.map { |p| p.encoded }
|
154
154
|
([preamble] + encoded_parts).join(crlf_boundary) + end_boundary + epilogue.to_s
|
155
155
|
else
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
156
|
+
dec = Mail::Encodings.get_encoding(encoding)
|
157
|
+
enc =
|
158
|
+
if Utilities.blank?(transfer_encoding)
|
159
|
+
dec
|
160
|
+
else
|
161
|
+
negotiate_best_encoding(transfer_encoding)
|
162
|
+
end
|
163
|
+
|
164
|
+
if dec.nil?
|
165
|
+
# Cannot decode, so skip normalization
|
166
|
+
raw_source
|
162
167
|
else
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
168
|
+
# Decode then encode to normalize and allow transforming
|
169
|
+
# from base64 to Q-P and vice versa
|
170
|
+
decoded = dec.decode(raw_source)
|
171
|
+
if defined?(Encoding) && charset && charset != "US-ASCII"
|
172
|
+
decoded = decoded.encode(charset)
|
173
|
+
decoded.force_encoding('BINARY') unless Encoding.find(charset).ascii_compatible?
|
174
|
+
end
|
175
|
+
enc.encode(decoded)
|
171
176
|
end
|
172
177
|
end
|
173
178
|
end
|
174
|
-
|
179
|
+
|
175
180
|
def decoded
|
176
181
|
if !Encodings.defined?(encoding)
|
177
182
|
raise UnknownEncodingType, "Don't know how to decode #{encoding}, please call #encoded and decode it yourself."
|
@@ -199,13 +204,14 @@ module Mail
|
|
199
204
|
@encoding
|
200
205
|
end
|
201
206
|
end
|
202
|
-
|
207
|
+
|
203
208
|
def encoding=( val )
|
204
|
-
@encoding =
|
205
|
-
|
206
|
-
|
209
|
+
@encoding =
|
210
|
+
if val == "text" || Utilities.blank?(val)
|
211
|
+
default_encoding
|
212
|
+
else
|
207
213
|
val
|
208
|
-
|
214
|
+
end
|
209
215
|
end
|
210
216
|
|
211
217
|
# Returns the preamble (any text that is before the first MIME boundary)
|
@@ -254,27 +260,58 @@ module Mail
|
|
254
260
|
@parts = Mail::PartsList.new[val]
|
255
261
|
end
|
256
262
|
end
|
257
|
-
|
263
|
+
|
258
264
|
def split!(boundary)
|
259
265
|
self.boundary = boundary
|
260
|
-
parts =
|
266
|
+
parts = extract_parts
|
267
|
+
|
261
268
|
# Make the preamble equal to the preamble (if any)
|
262
269
|
self.preamble = parts[0].to_s.strip
|
263
270
|
# Make the epilogue equal to the epilogue (if any)
|
264
|
-
self.epilogue = parts[-1].to_s.
|
271
|
+
self.epilogue = parts[-1].to_s.strip
|
265
272
|
parts[1...-1].to_a.each { |part| @parts << Mail::Part.new(part) }
|
266
273
|
self
|
267
274
|
end
|
268
|
-
|
269
|
-
def
|
270
|
-
|
275
|
+
|
276
|
+
def ascii_only?
|
277
|
+
unless defined? @ascii_only
|
278
|
+
@ascii_only = raw_source.ascii_only?
|
279
|
+
end
|
280
|
+
@ascii_only
|
271
281
|
end
|
272
|
-
|
282
|
+
|
273
283
|
def empty?
|
274
284
|
!!raw_source.to_s.empty?
|
275
285
|
end
|
276
|
-
|
286
|
+
|
287
|
+
def default_encoding
|
288
|
+
ascii_only? ? '7bit' : '8bit'
|
289
|
+
end
|
290
|
+
|
277
291
|
private
|
292
|
+
|
293
|
+
# split parts by boundary, ignore first part if empty, append final part when closing boundary was missing
|
294
|
+
def extract_parts
|
295
|
+
parts_regex = /
|
296
|
+
(?: # non-capturing group
|
297
|
+
\A | # start of string OR
|
298
|
+
\r\n # line break
|
299
|
+
)
|
300
|
+
(
|
301
|
+
--#{Regexp.escape(boundary || "")} # boundary delimiter
|
302
|
+
(?:--)? # with non-capturing optional closing
|
303
|
+
)
|
304
|
+
(?=\s*$) # lookahead matching zero or more spaces followed by line-ending
|
305
|
+
/x
|
306
|
+
parts = raw_source.split(parts_regex).each_slice(2).to_a
|
307
|
+
parts.each_with_index { |(part, _), index| parts.delete_at(index) if index > 0 && Utilities.blank?(part) }
|
308
|
+
|
309
|
+
if parts.size > 1
|
310
|
+
final_separator = parts[-2][1]
|
311
|
+
parts << [""] if final_separator != "--#{boundary}--"
|
312
|
+
end
|
313
|
+
parts.map(&:first)
|
314
|
+
end
|
278
315
|
|
279
316
|
def crlf_boundary
|
280
317
|
"\r\n--#{boundary}\r\n"
|
@@ -283,9 +320,9 @@ module Mail
|
|
283
320
|
def end_boundary
|
284
321
|
"\r\n--#{boundary}--\r\n"
|
285
322
|
end
|
286
|
-
|
323
|
+
|
287
324
|
def set_charset
|
288
|
-
|
325
|
+
@charset = ascii_only? ? 'US-ASCII' : nil
|
289
326
|
end
|
290
327
|
end
|
291
328
|
end
|