mail-portertech 2.6.2.edge

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 (153) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +753 -0
  3. data/CONTRIBUTING.md +60 -0
  4. data/Dependencies.txt +2 -0
  5. data/Gemfile +15 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +683 -0
  8. data/Rakefile +29 -0
  9. data/TODO.rdoc +9 -0
  10. data/lib/mail.rb +91 -0
  11. data/lib/mail/attachments_list.rb +104 -0
  12. data/lib/mail/body.rb +291 -0
  13. data/lib/mail/check_delivery_params.rb +20 -0
  14. data/lib/mail/configuration.rb +75 -0
  15. data/lib/mail/core_extensions/nil.rb +19 -0
  16. data/lib/mail/core_extensions/object.rb +13 -0
  17. data/lib/mail/core_extensions/smtp.rb +24 -0
  18. data/lib/mail/core_extensions/string.rb +43 -0
  19. data/lib/mail/core_extensions/string/access.rb +145 -0
  20. data/lib/mail/core_extensions/string/multibyte.rb +78 -0
  21. data/lib/mail/elements.rb +14 -0
  22. data/lib/mail/elements/address.rb +270 -0
  23. data/lib/mail/elements/address_list.rb +51 -0
  24. data/lib/mail/elements/content_disposition_element.rb +26 -0
  25. data/lib/mail/elements/content_location_element.rb +21 -0
  26. data/lib/mail/elements/content_transfer_encoding_element.rb +17 -0
  27. data/lib/mail/elements/content_type_element.rb +31 -0
  28. data/lib/mail/elements/date_time_element.rb +22 -0
  29. data/lib/mail/elements/envelope_from_element.rb +39 -0
  30. data/lib/mail/elements/message_ids_element.rb +24 -0
  31. data/lib/mail/elements/mime_version_element.rb +22 -0
  32. data/lib/mail/elements/phrase_list.rb +16 -0
  33. data/lib/mail/elements/received_element.rb +26 -0
  34. data/lib/mail/encodings.rb +304 -0
  35. data/lib/mail/encodings/7bit.rb +31 -0
  36. data/lib/mail/encodings/8bit.rb +31 -0
  37. data/lib/mail/encodings/base64.rb +33 -0
  38. data/lib/mail/encodings/binary.rb +31 -0
  39. data/lib/mail/encodings/quoted_printable.rb +39 -0
  40. data/lib/mail/encodings/transfer_encoding.rb +58 -0
  41. data/lib/mail/envelope.rb +30 -0
  42. data/lib/mail/field.rb +247 -0
  43. data/lib/mail/field_list.rb +33 -0
  44. data/lib/mail/fields.rb +35 -0
  45. data/lib/mail/fields/bcc_field.rb +56 -0
  46. data/lib/mail/fields/cc_field.rb +55 -0
  47. data/lib/mail/fields/comments_field.rb +41 -0
  48. data/lib/mail/fields/common/address_container.rb +16 -0
  49. data/lib/mail/fields/common/common_address.rb +135 -0
  50. data/lib/mail/fields/common/common_date.rb +35 -0
  51. data/lib/mail/fields/common/common_field.rb +57 -0
  52. data/lib/mail/fields/common/common_message_id.rb +48 -0
  53. data/lib/mail/fields/common/parameter_hash.rb +58 -0
  54. data/lib/mail/fields/content_description_field.rb +19 -0
  55. data/lib/mail/fields/content_disposition_field.rb +70 -0
  56. data/lib/mail/fields/content_id_field.rb +62 -0
  57. data/lib/mail/fields/content_location_field.rb +42 -0
  58. data/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
  59. data/lib/mail/fields/content_type_field.rb +201 -0
  60. data/lib/mail/fields/date_field.rb +57 -0
  61. data/lib/mail/fields/from_field.rb +55 -0
  62. data/lib/mail/fields/in_reply_to_field.rb +56 -0
  63. data/lib/mail/fields/keywords_field.rb +44 -0
  64. data/lib/mail/fields/message_id_field.rb +82 -0
  65. data/lib/mail/fields/mime_version_field.rb +53 -0
  66. data/lib/mail/fields/optional_field.rb +13 -0
  67. data/lib/mail/fields/received_field.rb +75 -0
  68. data/lib/mail/fields/references_field.rb +56 -0
  69. data/lib/mail/fields/reply_to_field.rb +55 -0
  70. data/lib/mail/fields/resent_bcc_field.rb +55 -0
  71. data/lib/mail/fields/resent_cc_field.rb +55 -0
  72. data/lib/mail/fields/resent_date_field.rb +35 -0
  73. data/lib/mail/fields/resent_from_field.rb +55 -0
  74. data/lib/mail/fields/resent_message_id_field.rb +34 -0
  75. data/lib/mail/fields/resent_sender_field.rb +62 -0
  76. data/lib/mail/fields/resent_to_field.rb +55 -0
  77. data/lib/mail/fields/return_path_field.rb +65 -0
  78. data/lib/mail/fields/sender_field.rb +67 -0
  79. data/lib/mail/fields/structured_field.rb +51 -0
  80. data/lib/mail/fields/subject_field.rb +16 -0
  81. data/lib/mail/fields/to_field.rb +55 -0
  82. data/lib/mail/fields/unstructured_field.rb +204 -0
  83. data/lib/mail/header.rb +274 -0
  84. data/lib/mail/indifferent_hash.rb +146 -0
  85. data/lib/mail/mail.rb +267 -0
  86. data/lib/mail/matchers/has_sent_mail.rb +157 -0
  87. data/lib/mail/message.rb +2160 -0
  88. data/lib/mail/multibyte.rb +42 -0
  89. data/lib/mail/multibyte/chars.rb +474 -0
  90. data/lib/mail/multibyte/exceptions.rb +8 -0
  91. data/lib/mail/multibyte/unicode.rb +400 -0
  92. data/lib/mail/multibyte/utils.rb +60 -0
  93. data/lib/mail/network.rb +14 -0
  94. data/lib/mail/network/delivery_methods/exim.rb +52 -0
  95. data/lib/mail/network/delivery_methods/file_delivery.rb +45 -0
  96. data/lib/mail/network/delivery_methods/sendmail.rb +89 -0
  97. data/lib/mail/network/delivery_methods/smtp.rb +142 -0
  98. data/lib/mail/network/delivery_methods/smtp_connection.rb +61 -0
  99. data/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
  100. data/lib/mail/network/retriever_methods/base.rb +63 -0
  101. data/lib/mail/network/retriever_methods/imap.rb +173 -0
  102. data/lib/mail/network/retriever_methods/pop3.rb +140 -0
  103. data/lib/mail/network/retriever_methods/test_retriever.rb +43 -0
  104. data/lib/mail/parsers.rb +26 -0
  105. data/lib/mail/parsers/address_lists_parser.rb +132 -0
  106. data/lib/mail/parsers/content_disposition_parser.rb +67 -0
  107. data/lib/mail/parsers/content_location_parser.rb +35 -0
  108. data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
  109. data/lib/mail/parsers/content_type_parser.rb +64 -0
  110. data/lib/mail/parsers/date_time_parser.rb +36 -0
  111. data/lib/mail/parsers/envelope_from_parser.rb +45 -0
  112. data/lib/mail/parsers/message_ids_parser.rb +39 -0
  113. data/lib/mail/parsers/mime_version_parser.rb +41 -0
  114. data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
  115. data/lib/mail/parsers/ragel.rb +17 -0
  116. data/lib/mail/parsers/ragel/common.rl +184 -0
  117. data/lib/mail/parsers/ragel/date_time.rl +30 -0
  118. data/lib/mail/parsers/ragel/parser_info.rb +61 -0
  119. data/lib/mail/parsers/ragel/ruby.rb +39 -0
  120. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
  121. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
  122. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
  123. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
  124. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
  125. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
  126. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
  127. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
  128. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
  129. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
  130. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
  131. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
  132. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2129 -0
  133. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
  134. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
  135. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
  136. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
  137. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
  138. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
  139. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
  140. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
  141. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
  142. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
  143. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
  144. data/lib/mail/parsers/received_parser.rb +47 -0
  145. data/lib/mail/part.rb +120 -0
  146. data/lib/mail/parts_list.rb +57 -0
  147. data/lib/mail/patterns.rb +37 -0
  148. data/lib/mail/utilities.rb +225 -0
  149. data/lib/mail/values/unicode_tables.dat +0 -0
  150. data/lib/mail/version.rb +4 -0
  151. data/lib/mail/version_specific/ruby_1_8.rb +119 -0
  152. data/lib/mail/version_specific/ruby_1_9.rb +159 -0
  153. metadata +276 -0
@@ -0,0 +1,60 @@
1
+ Contributing to Mail
2
+ ====================
3
+
4
+ Hi there, I welcome pull requests! Here are some thoughts on how to get your
5
+ pull request merged quickly:
6
+
7
+ 1. Check the Reference RFCs, they are in the References directory, so no excuses.
8
+ 2. Check for a ticket on GitHub, maybe someone else has the problem too
9
+ 3. Make a fork of my GitHub repository
10
+ 4. Run the specs. We only take pull requests with passing tests, and it's great
11
+ to know that you have a clean slate: `bundle && bundle exec rake`
12
+ 5. Add a spec for your change. Only refactoring and documentation changes
13
+ require no new specs. If you are adding functionality or fixing a bug, we need
14
+ a spec!
15
+ 6. Test the spec _at_ _least_ against MRI-1.9.3 and MRI-1.8.7
16
+ 7. Update the README if needed to reflect your change / addition
17
+ 8. Update the CHANGELOG and give yourself credit
18
+ 9. With all specs passing push your changes back to your fork
19
+ 10. Send me a pull request.
20
+ - If it needs any changes, please push or force push to the same branch you made the pull request from. GitHub will just update the pull request with your changes.
21
+
22
+ Note, specs that break MRI 1.8.7 or 1.9.3 will not be accepted.
23
+
24
+ At this point you're waiting on us. We like to at least comment on, if not
25
+ accept, pull requests within three business days (and, typically, one business
26
+ day). We may suggest some changes or improvements or alternatives.
27
+
28
+ Some things that will increase the chance that your pull request is accepted,
29
+ taken straight from the Ruby on Rails guide:
30
+
31
+ * Tell me you have tested it against more than one version of Ruby, RVM is great for
32
+ this. I test against 7 rubies before I push into master.
33
+ * Use good, idiomatic, structured and modular code
34
+ * Include tests that fail without your code, and pass with it
35
+ * Update the documentation, the surrounding one, examples elsewhere, guides,
36
+ whatever is affected by your contribution
37
+
38
+ Syntax:
39
+
40
+ * Two spaces, no tabs.
41
+ * No trailing whitespace. Blank lines should not have any space.
42
+ * Prefer &&/|| over and/or.
43
+ * MyClass.my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
44
+ * a = b and not a=b.
45
+ * Follow the conventions you see used in the source already.
46
+
47
+ And in case we didn't emphasize it enough: we love specs!
48
+
49
+ ### Testing against mime-types versions:
50
+
51
+ Use [appraisal](https://github.com/thoughtbot/appraisal) to run against all supported versions of mime-types.
52
+
53
+ 1. Run `(bundle check || bundle) && appraisal` so that all the 'appraised' gemfiles are bundled.
54
+ 2. Run either `appraisal rake` or `rake appraisal` to run all the tests.
55
+
56
+ To run only one 'appraised' gemfile, run. e.g. `BUNDLE_GEMFILE=gemfiles/mime_types_edge.gemfile (bundle check || bundle) && rake`
57
+
58
+ To change the appraisals, modify the `Appraisals` file, run `appraisal`, commit the generated gemfiles, and modify the .travis.yml matrix.
59
+
60
+ To run on all rubies / gemfiles, just like TravisCI, see [WWTD](https://github.com/grosser/wwtd).
@@ -0,0 +1,2 @@
1
+ tlsmail: if ruby < 1.8.6... we could make it optional, or embed it in Mail
2
+ mime/types: I think we embed a simplified version, or help maintain it, it is old (2006)
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "tlsmail", "~> 0.0.1" if RUBY_VERSION <= "1.8.6"
6
+ gem "jruby-openssl", :platforms => :jruby
7
+
8
+ group :development, :test do
9
+ gem "appraisal", "~> 1.0"
10
+ end
11
+
12
+ # For gems not required to run tests
13
+ group :local_development, :test do
14
+ gem "ruby-debug", :platforms => :mri_18
15
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009-2013 Mikel Lindsaar
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ 'Software'), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,683 @@
1
+ Mail [![Build Status](https://travis-ci.org/mikel/mail.png?branch=master)](https://travis-ci.org/mikel/mail)
2
+ ====
3
+
4
+ Introduction
5
+ ------------
6
+
7
+ Mail is an internet library for Ruby that is designed to handle emails
8
+ generation, parsing and sending in a simple, rubyesque manner.
9
+
10
+ The purpose of this library is to provide a single point of access to handle
11
+ all email functions, including sending and receiving emails. All network
12
+ type actions are done through proxy methods to Net::SMTP, Net::POP3 etc.
13
+
14
+ Built from my experience with TMail, it is designed to be a pure ruby
15
+ implementation that makes generating, sending and parsing emails a no
16
+ brainer.
17
+
18
+ It is also designed form the ground up to work with the more modern versions
19
+ of Ruby. This is because Ruby > 1.9 handles text encodings much more wonderfully
20
+ than Ruby 1.8.x and so these features have been taken full advantage of in this
21
+ library allowing Mail to handle a lot more messages more cleanly than TMail.
22
+ Mail does run on Ruby 1.8.x... it's just not as fun to code.
23
+
24
+ Finally, Mail has been designed with a very simple object oriented system
25
+ that really opens up the email messages you are parsing, if you know what
26
+ you are doing, you can fiddle with every last bit of your email directly.
27
+
28
+ Donations
29
+ -------------
30
+
31
+ Mail has been downloaded millions of times, by people around the world, in fact,
32
+ it represents more than 1% of *all* gems downloaded.
33
+
34
+ It is (like all open source software) a labour of love and something I am doing
35
+ with my own free time. If you would like to say thanks, please feel free to
36
+ [make a donation](http://www.pledgie.com/campaigns/8790) and feel free to send
37
+ me a nice email :)
38
+
39
+ <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
+
41
+
42
+ Compatibility
43
+ -------------
44
+
45
+ Every Mail commit is tested by Travis on the [following platforms](https://github.com/mikel/mail/blob/master/.travis.yml)
46
+
47
+ * ruby-1.8.7-p374 [ i686 ]
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 ]
56
+
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
+ ----------
65
+
66
+ If you want to discuss mail with like minded individuals, please subscribe to
67
+ the [Google Group](http://groups.google.com/group/mail-ruby).
68
+
69
+ Current Capabilities of Mail
70
+ ----------------------------
71
+
72
+ * RFC2822 Support, Reading and Writing
73
+ * RFC2045-2049 Support for multipart emails
74
+ * Support for creating multipart alternate emails
75
+ * 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
+ * Wrappers for File, Net/POP3, Net/SMTP
78
+ * Auto encoding of non US-ASCII header fields
79
+ * Auto encoding of non US-ASCII bodies
80
+
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.
87
+
88
+ This means Mail won't (ever) crunch your data (I think).
89
+
90
+ You can also create MIME emails. There are helper methods for making a
91
+ multipart/alternate email for text/plain and text/html (the most common pair)
92
+ and you can manually create any other type of MIME email.
93
+
94
+ Roadmap
95
+ -------
96
+
97
+ Next TODO:
98
+
99
+ * Improve MIME support for character sets in headers, currently works, mostly, needs
100
+ refinement.
101
+
102
+ Testing Policy
103
+ --------------
104
+
105
+ Basically... we do BDD on Mail. No method gets written in Mail without a
106
+ corresponding or covering spec. We expect as a minimum 100% coverage
107
+ measured by RCov. While this is not perfect by any measure, it is pretty
108
+ good. Additionally, all functional tests from TMail are to be passing before
109
+ the gem gets released.
110
+
111
+ It also means you can be sure Mail will behave correctly.
112
+
113
+ API Policy
114
+ ----------
115
+
116
+ No API removals within a single point release. All removals to be deprecated with
117
+ warnings for at least one MINOR point release before removal.
118
+
119
+ Also, all private or protected methods to be declared as such - though this is still I/P.
120
+
121
+ Installation
122
+ ------------
123
+
124
+ Installation is fairly simple, I host mail on rubygems, so you can just do:
125
+
126
+ # gem install mail
127
+
128
+ Encodings
129
+ ---------
130
+
131
+ If you didn't know, handling encodings in Emails is not as straight forward as you
132
+ would hope.
133
+
134
+ I have tried to simplify it some:
135
+
136
+ 1. All objects that can render into an email, have an `#encoded` method. Encoded will
137
+ return the object as a complete string ready to send in the mail system, that is,
138
+ it will include the header field and value and CRLF at the end and wrapped as
139
+ needed.
140
+
141
+ 2. All objects that can render into an email, have a `#decoded` method. Decoded will
142
+ return the object's "value" only as a string. This means it will not include
143
+ the header fields (like 'To:' or 'Subject:').
144
+
145
+ 3. By default, calling <code>#to_s</code> on a container object will call its encoded
146
+ method, while <code>#to_s</code> on a field object will call its decoded method.
147
+ So calling <code>#to_s</code> on a Mail object will return the mail, all encoded
148
+ ready to send, while calling <code>#to_s</code> on the From field or the body will
149
+ return the decoded value of the object. The header object of Mail is considered a
150
+ container. If you are in doubt, call <code>#encoded</code>, or <code>#decoded</code>
151
+ explicitly, this is safer if you are not sure.
152
+
153
+ 4. Structured fields that have parameter values that can be encoded (e.g. Content-Type) will
154
+ provide decoded parameter values when you call the parameter names as methods against
155
+ the object.
156
+
157
+ 5. Structured fields that have parameter values that can be encoded (e.g. Content-Type) will
158
+ provide encoded parameter values when you call the parameter names through the
159
+ <code>object.parameters['<parameter_name>']</code> method call.
160
+
161
+ Contributing
162
+ ------------
163
+
164
+ Please do! Contributing is easy in Mail. Please read the CONTRIBUTING.md document for more info
165
+
166
+ Usage
167
+ -----
168
+
169
+ All major mail functions should be able to happen from the Mail module.
170
+ So, you should be able to just <code>require 'mail'</code> to get started.
171
+
172
+ ### Making an email
173
+
174
+ ```ruby
175
+ mail = Mail.new do
176
+ from 'mikel@test.lindsaar.net'
177
+ to 'you@test.lindsaar.net'
178
+ subject 'This is a test email'
179
+ body File.read('body.txt')
180
+ end
181
+
182
+ mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...
183
+ ```
184
+
185
+ ### Making an email, have it your way:
186
+
187
+ ```ruby
188
+ mail = Mail.new do
189
+ body File.read('body.txt')
190
+ end
191
+
192
+ mail['from'] = 'mikel@test.lindsaar.net'
193
+ mail[:to] = 'you@test.lindsaar.net'
194
+ mail.subject = 'This is a test email'
195
+
196
+ mail.header['X-Custom-Header'] = 'custom value'
197
+
198
+ mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...
199
+ ```
200
+
201
+ ### Don't Worry About Message IDs:
202
+
203
+ ```ruby
204
+ mail = Mail.new do
205
+ to 'you@test.lindsaar.net'
206
+ body 'Some simple body'
207
+ end
208
+
209
+ mail.to_s =~ /Message\-ID: <[\d\w_]+@.+.mail/ #=> 27
210
+ ```
211
+
212
+ Mail will automatically add a Message-ID field if it is missing and
213
+ give it a unique, random Message-ID along the lines of:
214
+
215
+ <4a7ff76d7016_13a81ab802e1@local.host.mail>
216
+
217
+ ### Or do worry about Message-IDs:
218
+
219
+ ```ruby
220
+ mail = Mail.new do
221
+ to 'you@test.lindsaar.net'
222
+ message_id '<ThisIsMyMessageId@some.domain.com>'
223
+ body 'Some simple body'
224
+ end
225
+
226
+ mail.to_s =~ /Message\-ID: <ThisIsMyMessageId@some.domain.com>/ #=> 27
227
+ ```
228
+
229
+ Mail will take the message_id you assign to it trusting that you know
230
+ what you are doing.
231
+
232
+ ### Sending an email:
233
+
234
+ Mail defaults to sending via SMTP to local host port 25. If you have a
235
+ sendmail or postfix daemon running on on this port, sending email is as
236
+ easy as:
237
+
238
+ ```ruby
239
+ Mail.deliver do
240
+ from 'me@test.lindsaar.net'
241
+ to 'you@test.lindsaar.net'
242
+ subject 'Here is the image you wanted'
243
+ body File.read('body.txt')
244
+ add_file '/full/path/to/somefile.png'
245
+ end
246
+ ```
247
+
248
+ or
249
+
250
+ ```ruby
251
+ mail = Mail.new do
252
+ from 'me@test.lindsaar.net'
253
+ to 'you@test.lindsaar.net'
254
+ subject 'Here is the image you wanted'
255
+ body File.read('body.txt')
256
+ add_file :filename => 'somefile.png', :content => File.read('/somefile.png')
257
+ end
258
+
259
+ mail.deliver!
260
+ ```
261
+
262
+ Sending via sendmail can be done like so:
263
+
264
+ ```ruby
265
+ mail = Mail.new do
266
+ from 'me@test.lindsaar.net'
267
+ to 'you@test.lindsaar.net'
268
+ subject 'Here is the image you wanted'
269
+ body File.read('body.txt')
270
+ add_file :filename => 'somefile.png', :content => File.read('/somefile.png')
271
+ end
272
+
273
+ mail.delivery_method :sendmail
274
+
275
+ mail.deliver
276
+ ```
277
+
278
+ Sending via smtp (for example to [mailcatcher](https://github.com/sj26/mailcatcher))
279
+ ```ruby
280
+
281
+ Mail.defaults do
282
+ delivery_method :smtp, address: "localhost", port: 1025
283
+ end
284
+ ```
285
+
286
+
287
+ Exim requires its own delivery manager, and can be used like so:
288
+
289
+ ```ruby
290
+ mail.delivery_method :exim, :location => "/usr/bin/exim"
291
+
292
+ mail.deliver
293
+ ```
294
+
295
+ ### Getting emails from a pop server:
296
+
297
+ You can configure Mail to receive email using <code>retriever_method</code>
298
+ within <code>Mail.defaults</code>:
299
+
300
+ ```ruby
301
+ Mail.defaults do
302
+ retriever_method :pop3, :address => "pop.gmail.com",
303
+ :port => 995,
304
+ :user_name => '<username>',
305
+ :password => '<password>',
306
+ :enable_ssl => true
307
+ end
308
+ ```
309
+
310
+ You can access incoming email in a number of ways.
311
+
312
+ The most recent email:
313
+
314
+ ```ruby
315
+ Mail.all #=> Returns an array of all emails
316
+ Mail.first #=> Returns the first unread email
317
+ Mail.last #=> Returns the last unread email
318
+ ```
319
+
320
+ The first 10 emails sorted by date in ascending order:
321
+
322
+ ```ruby
323
+ emails = Mail.find(:what => :first, :count => 10, :order => :asc)
324
+ emails.length #=> 10
325
+ ```
326
+
327
+ Or even all emails:
328
+
329
+ ```ruby
330
+ emails = Mail.all
331
+ emails.length #=> LOTS!
332
+ ```
333
+
334
+
335
+ ### Reading an Email
336
+
337
+ ```ruby
338
+ mail = Mail.read('/path/to/message.eml')
339
+
340
+ mail.envelope_from #=> 'mikel@test.lindsaar.net'
341
+ mail.from.addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
342
+ mail.sender.address #=> 'mikel@test.lindsaar.net'
343
+ mail.to #=> 'bob@test.lindsaar.net'
344
+ mail.cc #=> 'sam@test.lindsaar.net'
345
+ mail.subject #=> "This is the subject"
346
+ mail.date.to_s #=> '21 Nov 1997 09:55:06 -0600'
347
+ mail.message_id #=> '<4D6AA7EB.6490534@xxx.xxx>'
348
+ mail.body.decoded #=> 'This is the body of the email...
349
+ ```
350
+
351
+ Many more methods available.
352
+
353
+ ### Reading a Multipart Email
354
+
355
+ ```ruby
356
+ mail = Mail.read('multipart_email')
357
+
358
+ mail.multipart? #=> true
359
+ mail.parts.length #=> 2
360
+ mail.body.preamble #=> "Text before the first part"
361
+ mail.body.epilogue #=> "Text after the last part"
362
+ mail.parts.map { |p| p.content_type } #=> ['text/plain', 'application/pdf']
363
+ mail.parts.map { |p| p.class } #=> [Mail::Message, Mail::Message]
364
+ mail.parts[0].content_type_parameters #=> {'charset' => 'ISO-8859-1'}
365
+ mail.parts[1].content_type_parameters #=> {'name' => 'my.pdf'}
366
+ ```
367
+
368
+ Mail generates a tree of parts. Each message has many or no parts. Each part
369
+ is another message which can have many or no parts.
370
+
371
+ A message will only have parts if it is a multipart/mixed or multipart/related
372
+ content type and has a boundary defined.
373
+
374
+ ### Testing and extracting attachments
375
+ ```ruby
376
+ mail.attachments.each do | attachment |
377
+ # Attachments is an AttachmentsList object containing a
378
+ # number of Part objects
379
+ if (attachment.content_type.start_with?('image/'))
380
+ # extracting images for example...
381
+ filename = attachment.filename
382
+ begin
383
+ File.open(images_dir + filename, "w+b", 0644) {|f| f.write attachment.body.decoded}
384
+ rescue => e
385
+ puts "Unable to save data for #{filename} because #{e.message}"
386
+ end
387
+ end
388
+ end
389
+ ```
390
+ ### Writing and sending a multipart/alternative (html and text) email
391
+
392
+ Mail makes some basic assumptions and makes doing the common thing as
393
+ simple as possible.... (asking a lot from a mail library)
394
+
395
+ ```ruby
396
+ mail = Mail.deliver do
397
+ to 'nicolas@test.lindsaar.net.au'
398
+ from 'Mikel Lindsaar <mikel@test.lindsaar.net.au>'
399
+ subject 'First multipart email sent with Mail'
400
+
401
+ text_part do
402
+ body 'This is plain text'
403
+ end
404
+
405
+ html_part do
406
+ content_type 'text/html; charset=UTF-8'
407
+ body '<h1>This is HTML</h1>'
408
+ end
409
+ end
410
+ ```
411
+
412
+ Mail then delivers the email at the end of the block and returns the
413
+ resulting Mail::Message object, which you can then inspect if you
414
+ so desire...
415
+
416
+ ```
417
+ puts mail.to_s #=>
418
+
419
+ To: nicolas@test.lindsaar.net.au
420
+ From: Mikel Lindsaar <mikel@test.lindsaar.net.au>
421
+ Subject: First multipart email sent with Mail
422
+ Content-Type: multipart/alternative;
423
+ boundary=--==_mimepart_4a914f0c911be_6f0f1ab8026659
424
+ Message-ID: <4a914f12ac7e_6f0f1ab80267d1@baci.local.mail>
425
+ Date: Mon, 24 Aug 2009 00:15:46 +1000
426
+ Mime-Version: 1.0
427
+ Content-Transfer-Encoding: 7bit
428
+
429
+
430
+ ----==_mimepart_4a914f0c911be_6f0f1ab8026659
431
+ Content-ID: <4a914f12c8c4_6f0f1ab80268d6@baci.local.mail>
432
+ Date: Mon, 24 Aug 2009 00:15:46 +1000
433
+ Mime-Version: 1.0
434
+ Content-Type: text/plain
435
+ Content-Transfer-Encoding: 7bit
436
+
437
+ This is plain text
438
+ ----==_mimepart_4a914f0c911be_6f0f1ab8026659
439
+ Content-Type: text/html; charset=UTF-8
440
+ Content-ID: <4a914f12cf86_6f0f1ab802692c@baci.local.mail>
441
+ Date: Mon, 24 Aug 2009 00:15:46 +1000
442
+ Mime-Version: 1.0
443
+ Content-Transfer-Encoding: 7bit
444
+
445
+ <h1>This is HTML</h1>
446
+ ----==_mimepart_4a914f0c911be_6f0f1ab8026659--
447
+ ```
448
+
449
+ Mail inserts the content transfer encoding, the mime version,
450
+ the content-id's and handles the content-type and boundary.
451
+
452
+ Mail assumes that if your text in the body is only us-ascii, that your
453
+ transfer encoding is 7bit and it is text/plain. You can override this
454
+ by explicitly declaring it.
455
+
456
+ ### Making Multipart/Alternate, without a block
457
+
458
+ You don't have to use a block with the text and html part included, you
459
+ can just do it declaratively. However, you need to add Mail::Parts to
460
+ an email, not Mail::Messages.
461
+
462
+ ```ruby
463
+ mail = Mail.new do
464
+ to 'nicolas@test.lindsaar.net.au'
465
+ from 'Mikel Lindsaar <mikel@test.lindsaar.net.au>'
466
+ subject 'First multipart email sent with Mail'
467
+ end
468
+
469
+ text_part = Mail::Part.new do
470
+ body 'This is plain text'
471
+ end
472
+
473
+ html_part = Mail::Part.new do
474
+ content_type 'text/html; charset=UTF-8'
475
+ body '<h1>This is HTML</h1>'
476
+ end
477
+
478
+ mail.text_part = text_part
479
+ mail.html_part = html_part
480
+ ```
481
+
482
+ Results in the same email as done using the block form
483
+
484
+ ### Getting error reports from an email:
485
+
486
+ ```ruby
487
+ @mail = Mail.read('/path/to/bounce_message.eml')
488
+
489
+ @mail.bounced? #=> true
490
+ @mail.final_recipient #=> rfc822;mikel@dont.exist.com
491
+ @mail.action #=> failed
492
+ @mail.error_status #=> 5.5.0
493
+ @mail.diagnostic_code #=> smtp;550 Requested action not taken: mailbox unavailable
494
+ @mail.retryable? #=> false
495
+ ```
496
+
497
+ ### Attaching and Detaching Files
498
+
499
+ You can just read the file off an absolute path, Mail will try
500
+ to guess the mime_type and will encode the file in Base64 for you.
501
+
502
+ ```ruby
503
+ @mail = Mail.new
504
+ @mail.add_file("/path/to/file.jpg")
505
+ @mail.parts.first.attachment? #=> true
506
+ @mail.parts.first.content_transfer_encoding.to_s #=> 'base64'
507
+ @mail.attachments.first.mime_type #=> 'image/jpg'
508
+ @mail.attachments.first.filename #=> 'file.jpg'
509
+ @mail.attachments.first.decoded == File.read('/path/to/file.jpg') #=> true
510
+ ```
511
+
512
+ Or You can pass in file_data and give it a filename, again, mail
513
+ will try and guess the mime_type for you.
514
+
515
+ ```ruby
516
+ @mail = Mail.new
517
+ @mail.attachments['myfile.pdf'] = File.read('path/to/myfile.pdf')
518
+ @mail.parts.first.attachment? #=> true
519
+ @mail.attachments.first.mime_type #=> 'application/pdf'
520
+ @mail.attachments.first.decoded == File.read('path/to/myfile.pdf') #=> true
521
+ ```
522
+
523
+ You can also override the guessed MIME media type if you really know better
524
+ than mail (this should be rarely needed)
525
+
526
+ ```ruby
527
+ @mail = Mail.new
528
+ file_data = File.read('path/to/myfile.pdf')
529
+ @mail.attachments['myfile.pdf'] = { :mime_type => 'application/x-pdf',
530
+ :content => File.read('path/to/myfile.pdf') }
531
+ @mail.parts.first.mime_type #=> 'application/x-pdf'
532
+ ```
533
+
534
+ Of course... Mail will round trip an attachment as well
535
+
536
+ ```ruby
537
+ @mail = Mail.new do
538
+ to 'nicolas@test.lindsaar.net.au'
539
+ from 'Mikel Lindsaar <mikel@test.lindsaar.net.au>'
540
+ subject 'First multipart email sent with Mail'
541
+
542
+ text_part do
543
+ body 'Here is the attachment you wanted'
544
+ end
545
+
546
+ html_part do
547
+ content_type 'text/html; charset=UTF-8'
548
+ body '<h1>Funky Title</h1><p>Here is the attachment you wanted</p>'
549
+ end
550
+
551
+ add_file '/path/to/myfile.pdf'
552
+ end
553
+
554
+ @round_tripped_mail = Mail.new(@mail.encoded)
555
+
556
+ @round_tripped_mail.attachments.length #=> 1
557
+ @round_tripped_mail.attachments.first.filename #=> 'myfile.pdf'
558
+ ```
559
+ See "Testing and extracting attachments" above for more details.
560
+
561
+ Using Mail with Testing or Spec'ing Libraries
562
+ ---------------------------------------------
563
+
564
+ If mail is part of your system, you'll need a way to test it without actually
565
+ sending emails, the TestMailer can do this for you.
566
+
567
+ ```ruby
568
+ require 'mail'
569
+ => true
570
+ Mail.defaults do
571
+ delivery_method :test
572
+ end
573
+ => #<Mail::Configuration:0x19345a8 @delivery_method=Mail::TestMailer>
574
+ Mail::TestMailer.deliveries
575
+ => []
576
+ Mail.deliver do
577
+ to 'mikel@me.com'
578
+ from 'you@you.com'
579
+ subject 'testing'
580
+ body 'hello'
581
+ end
582
+ => #<Mail::Message:0x19284ec ...
583
+ Mail::TestMailer.deliveries.length
584
+ => 1
585
+ Mail::TestMailer.deliveries.first
586
+ => #<Mail::Message:0x19284ec ...
587
+ Mail::TestMailer.deliveries.clear
588
+ => []
589
+ ```
590
+
591
+ There is also a set of RSpec matchers stolen fr^H^H^H^H^H^H^H^H inspired by Shoulda's ActionMailer matchers (you'll want to set <code>delivery_method</code> as above too):
592
+
593
+ ```ruby
594
+ Mail.defaults do
595
+ delivery_method :test # in practice you'd do this in spec_helper.rb
596
+ end
597
+
598
+ describe "sending an email" do
599
+ include Mail::Matchers
600
+
601
+ before(:each) do
602
+ Mail::TestMailer.deliveries.clear
603
+
604
+ Mail.deliver do
605
+ to ['mikel@me.com', 'mike2@me.com']
606
+ from 'you@you.com'
607
+ subject 'testing'
608
+ body 'hello'
609
+ end
610
+ end
611
+
612
+ it { should have_sent_email } # passes if any email at all was sent
613
+
614
+ it { should have_sent_email.from('you@you.com') }
615
+ it { should have_sent_email.to('mike1@me.com') }
616
+
617
+ # can specify a list of recipients...
618
+ it { should have_sent_email.to(['mike1@me.com', 'mike2@me.com']) }
619
+
620
+ # ...or chain recipients together
621
+ it { should have_sent_email.to('mike1@me.com').to('mike2@me.com') }
622
+
623
+ it { should have_sent_email.with_subject('testing') }
624
+
625
+ it { should have_sent_email.with_body('hello') }
626
+
627
+ # Can match subject or body with a regex
628
+ # (or anything that responds_to? :match)
629
+
630
+ it { should have_sent_email.matching_subject(/test(ing)?/) }
631
+ it { should have_sent_email.matching_body(/h(a|e)llo/) }
632
+
633
+ # Can chain together modifiers
634
+ # Note that apart from recipients, repeating a modifier overwrites old value.
635
+
636
+ it { should have_sent_email.from('you@you.com').to('mike1@me.com').matching_body(/hell/)
637
+ end
638
+ ```
639
+
640
+ Excerpts from TREC Spam Corpus 2005
641
+ -----------------------------------
642
+
643
+ The spec fixture files in spec/fixtures/emails/from_trec_2005 are from the
644
+ 2005 TREC Public Spam Corpus. They remain copyrighted under the terms of
645
+ that project and license agreement. They are used in this project to verify
646
+ and describe the development of this email parser implementation.
647
+
648
+ http://plg.uwaterloo.ca/~gvcormac/treccorpus/
649
+
650
+ They are used as allowed by 'Permitted Uses, Clause 3':
651
+
652
+ "Small excerpts of the information may be displayed to others
653
+ or published in a scientific or technical context, solely for
654
+ the purpose of describing the research and development and
655
+ related issues."
656
+
657
+ -- http://plg.uwaterloo.ca/~gvcormac/treccorpus/
658
+
659
+ License
660
+ -------
661
+
662
+ (The MIT License)
663
+
664
+ Copyright (c) 2009-2013 Mikel Lindsaar
665
+
666
+ Permission is hereby granted, free of charge, to any person obtaining
667
+ a copy of this software and associated documentation files (the
668
+ 'Software'), to deal in the Software without restriction, including
669
+ without limitation the rights to use, copy, modify, merge, publish,
670
+ distribute, sublicense, and/or sell copies of the Software, and to
671
+ permit persons to whom the Software is furnished to do so, subject to
672
+ the following conditions:
673
+
674
+ The above copyright notice and this permission notice shall be
675
+ included in all copies or substantial portions of the Software.
676
+
677
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
678
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
679
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
680
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
681
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
682
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
683
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.