mail 2.5.4 → 2.6.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 +7 -0
- data/CHANGELOG.rdoc +7 -2
- data/CONTRIBUTING.md +13 -0
- data/Dependencies.txt +0 -1
- data/Gemfile +9 -7
- data/README.md +41 -21
- data/Rakefile +10 -2
- data/VERSION +4 -0
- data/lib/mail/body.rb +2 -2
- data/lib/mail/core_extensions/string.rb +12 -2
- data/lib/mail/elements/address.rb +38 -82
- data/lib/mail/elements/address_list.rb +19 -42
- data/lib/mail/elements/content_disposition_element.rb +3 -7
- data/lib/mail/elements/content_location_element.rb +2 -6
- data/lib/mail/elements/content_transfer_encoding_element.rb +3 -10
- data/lib/mail/elements/content_type_element.rb +4 -8
- data/lib/mail/elements/date_time_element.rb +3 -7
- data/lib/mail/elements/envelope_from_element.rb +3 -11
- data/lib/mail/elements/message_ids_element.rb +1 -6
- data/lib/mail/elements/mime_version_element.rb +3 -7
- data/lib/mail/elements/phrase_list.rb +2 -7
- data/lib/mail/elements/received_element.rb +3 -7
- data/lib/mail/encodings.rb +0 -1
- data/lib/mail/envelope.rb +0 -5
- data/lib/mail/field.rb +53 -17
- data/lib/mail/field_list.rb +18 -18
- data/lib/mail/fields/common/common_address.rb +15 -20
- data/lib/mail/fields/common/common_date.rb +0 -7
- data/lib/mail/fields/common/common_field.rb +1 -1
- data/lib/mail/fields/content_transfer_encoding_field.rb +0 -6
- data/lib/mail/fields/resent_sender_field.rb +1 -1
- data/lib/mail/fields/sender_field.rb +1 -1
- data/lib/mail/fields/unstructured_field.rb +7 -1
- data/lib/mail/header.rb +8 -22
- data/lib/mail/mail.rb +12 -0
- data/lib/mail/matchers/has_sent_mail.rb +34 -1
- data/lib/mail/message.rb +18 -11
- data/lib/mail/multibyte/unicode.rb +1 -1
- data/lib/mail/network/delivery_methods/sendmail.rb +1 -1
- data/lib/mail/network/delivery_methods/smtp.rb +5 -9
- data/lib/mail/network/retriever_methods/imap.rb +18 -13
- data/lib/mail/parsers/address_lists_parser.rb +132 -0
- data/lib/mail/parsers/content_disposition_parser.rb +67 -0
- data/lib/mail/parsers/content_location_parser.rb +35 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
- data/lib/mail/parsers/content_type_parser.rb +64 -0
- data/lib/mail/parsers/date_time_parser.rb +36 -0
- data/lib/mail/parsers/envelope_from_parser.rb +45 -0
- data/lib/mail/parsers/message_ids_parser.rb +39 -0
- data/lib/mail/parsers/mime_version_parser.rb +41 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
- data/lib/mail/parsers/ragel/common.rl +184 -0
- data/lib/mail/parsers/ragel/date_time.rl +30 -0
- data/lib/mail/parsers/ragel/parser_info.rb +61 -0
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2129 -0
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
- data/lib/mail/parsers/ragel/ruby.rb +29 -0
- data/lib/mail/parsers/ragel.rb +17 -0
- data/lib/mail/parsers/received_parser.rb +47 -0
- data/lib/mail/parsers.rb +26 -0
- data/lib/mail/parts_list.rb +5 -3
- data/lib/mail/patterns.rb +3 -1
- data/lib/mail/utilities.rb +3 -1
- data/lib/mail/version.rb +1 -1
- data/lib/mail/version_specific/ruby_1_8.rb +1 -1
- data/lib/mail/version_specific/ruby_1_9.rb +16 -1
- data/lib/mail.rb +1 -1
- metadata +77 -87
- data/lib/VERSION +0 -4
- data/lib/load_parsers.rb +0 -35
- data/lib/mail/parsers/address_lists.rb +0 -64
- data/lib/mail/parsers/address_lists.treetop +0 -19
- data/lib/mail/parsers/content_disposition.rb +0 -535
- data/lib/mail/parsers/content_disposition.treetop +0 -46
- data/lib/mail/parsers/content_location.rb +0 -139
- data/lib/mail/parsers/content_location.treetop +0 -20
- data/lib/mail/parsers/content_transfer_encoding.rb +0 -201
- data/lib/mail/parsers/content_transfer_encoding.treetop +0 -18
- data/lib/mail/parsers/content_type.rb +0 -971
- data/lib/mail/parsers/content_type.treetop +0 -68
- data/lib/mail/parsers/date_time.rb +0 -114
- data/lib/mail/parsers/date_time.treetop +0 -11
- data/lib/mail/parsers/envelope_from.rb +0 -194
- data/lib/mail/parsers/envelope_from.treetop +0 -32
- data/lib/mail/parsers/message_ids.rb +0 -45
- data/lib/mail/parsers/message_ids.treetop +0 -15
- data/lib/mail/parsers/mime_version.rb +0 -144
- data/lib/mail/parsers/mime_version.treetop +0 -19
- data/lib/mail/parsers/phrase_lists.rb +0 -45
- data/lib/mail/parsers/phrase_lists.treetop +0 -15
- data/lib/mail/parsers/received.rb +0 -71
- data/lib/mail/parsers/received.treetop +0 -11
- data/lib/mail/parsers/rfc2045.rb +0 -421
- data/lib/mail/parsers/rfc2045.treetop +0 -35
- data/lib/mail/parsers/rfc2822.rb +0 -5397
- data/lib/mail/parsers/rfc2822.treetop +0 -408
- data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
- data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
- data/lib/tasks/corpus.rake +0 -125
- data/lib/tasks/treetop.rake +0 -10
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: ecb5e9115e61802f251480eef90c6698ac665d0b
|
|
4
|
+
data.tar.gz: a1105d5defc2c7b374598a392e5f5dc4d1452a21
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 103d2126c02d1aeb5ffd4982f261407af16652fd181f6e0fc63bf12702e5aa1ea3c7f863a3c39f822ba3b8e8cf704782d1beb7c4e2e28cba5f4fc2931151cf0e
|
|
7
|
+
data.tar.gz: 6f25c0decaf77a0314b42d0fbf6c61edfc7f2fe9b4bbeef004e34a7127882093b660108cd7728a108f26b1b3dcf2664beac4e5e6d0d0d3e68565f78fdd273d4e
|
data/CHANGELOG.rdoc
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
== HEAD
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
== Version 2.5.4 - Tue May 14 14:45:00 +1100 2013 Mikel Lindsaar <mikel@lindsaar.net>
|
|
3
|
+
== Version 2.6.0 - Mon Jun 2 22:49 +1100 2014 Mikel Lindsaar <mikel@reinteractive.net>
|
|
5
4
|
|
|
6
5
|
Features:
|
|
6
|
+
* Allow interceptors and observers to be unregistered (zuhao)
|
|
7
|
+
* Added feature to find the mail in uid (taketin)
|
|
7
8
|
* Save settings passed to TestMailer#new (svanderbleek)
|
|
8
9
|
* Allow the setting of envelope from directly (jeremy)
|
|
9
10
|
* Accept other IETF/IANA-registered Content-Types and Content-Transfer-Encodings (jeremy)
|
|
@@ -19,9 +20,13 @@ Features:
|
|
|
19
20
|
* Close pull request 389 - Don't add superfluous message headers to MIME parts (djmaze, jeremy)
|
|
20
21
|
|
|
21
22
|
Performance:
|
|
23
|
+
* Migrate to RAGEL based parser, awesome work by (bpot)
|
|
24
|
+
* Performance improvements for people parsing email headers (ConradIrwin)
|
|
22
25
|
* Close pull request 488 - Speed up field construction & comparison (bpot)
|
|
23
26
|
|
|
24
27
|
Bugs:
|
|
28
|
+
* Fix for when content looks like field name (kjg)
|
|
29
|
+
* Don't change original when you change a copy (TylerRick)
|
|
25
30
|
* Don't include separating semicolon in paramter value when sanitizing (bpot)
|
|
26
31
|
* Fix fencepost encoding problem with binhex strings and only one token (drasch)
|
|
27
32
|
* Fix sendmail delivery to addresses with a leading hyphen (lifo, jeremy)
|
data/CONTRIBUTING.md
CHANGED
|
@@ -43,3 +43,16 @@ Syntax:
|
|
|
43
43
|
* Follow the conventions you see used in the source already.
|
|
44
44
|
|
|
45
45
|
And in case we didn't emphasize it enough: we love specs!
|
|
46
|
+
|
|
47
|
+
### Testing against mime-types versions:
|
|
48
|
+
|
|
49
|
+
Use [appraisal](https://github.com/thoughtbot/appraisal) to run against all supported versions of mime-types.
|
|
50
|
+
|
|
51
|
+
1. Run `(bundle check || bundle) && appraisal` so that all the 'appraised' gemfiles are bundled.
|
|
52
|
+
2. Run either `appraisal rake` or `rake appraisal` to run all the tests.
|
|
53
|
+
|
|
54
|
+
To run only one 'appraised' gemfile, run. e.g. `BUNDLE_GEMFILE=gemfiles/mime_types_edge.gemfile (bundle check || bundle) && rake`
|
|
55
|
+
|
|
56
|
+
To change the appraisals, modify the `Appraisals` file, run `appraisal`, commit the generated gemfiles, and modify the .travis.yml matrix.
|
|
57
|
+
|
|
58
|
+
To run on all rubies / gemfiles, just like TravisCI, see [WWTD](https://github.com/grosser/wwtd).
|
data/Dependencies.txt
CHANGED
data/Gemfile
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
source
|
|
1
|
+
source "https://rubygems.org"
|
|
2
2
|
|
|
3
3
|
gemspec
|
|
4
4
|
|
|
5
|
-
gem "
|
|
6
|
-
gem "
|
|
7
|
-
gem "tlsmail" if RUBY_VERSION <= '1.8.6'
|
|
5
|
+
gem "tlsmail", "~> 0.0.1" if RUBY_VERSION <= "1.8.6"
|
|
6
|
+
gem "jruby-openssl", :platforms => :jruby
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
group :development, :test do
|
|
9
|
+
gem "appraisal", "~> 1.0"
|
|
10
|
+
end
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
# For gems not required to run tests
|
|
13
|
+
group :local_development, :test do
|
|
14
|
+
gem "ruby-debug", :platforms => :mri_18
|
|
13
15
|
end
|
data/README.md
CHANGED
|
@@ -15,11 +15,11 @@ Built from my experience with TMail, it is designed to be a pure ruby
|
|
|
15
15
|
implementation that makes generating, sending and parsing emails a no
|
|
16
16
|
brainer.
|
|
17
17
|
|
|
18
|
-
It is also designed form the ground up to work with
|
|
19
|
-
Ruby 1.9 handles text encodings much more
|
|
20
|
-
these features have been taken full advantage of in this
|
|
21
|
-
Mail to handle a lot more messages more cleanly than TMail.
|
|
22
|
-
Ruby 1.8.x... it's just not as fun to code.
|
|
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
23
|
|
|
24
24
|
Finally, Mail has been designed with a very simple object oriented system
|
|
25
25
|
that really opens up the email messages you are parsing, if you know what
|
|
@@ -44,14 +44,23 @@ Compatibility
|
|
|
44
44
|
|
|
45
45
|
Every Mail commit is tested by Travis on the [following platforms](https://github.com/mikel/mail/blob/master/.travis.yml)
|
|
46
46
|
|
|
47
|
-
* ruby-1.8.7-
|
|
48
|
-
* ruby-1.9.2-
|
|
47
|
+
* ruby-1.8.7-p374 [ i686 ]
|
|
48
|
+
* ruby-1.9.2-p320 [ x86_64 ]
|
|
49
49
|
* ruby-1.9.3-p327 [ x86_64 ]
|
|
50
|
-
* ruby-2.0.0-
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
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
|
+
$ BUNDLE_GEMFILE=gemfiles/mime_types_1.16.gemfile bundle check
|
|
60
|
+
$ BUNDLE_GEMFILE=gemfiles/mime_types_1.16.gemfile bundle
|
|
61
|
+
$ BUNDLE_GEMFILE=gemfiles/mime_types_1.16.gemfile rake
|
|
62
|
+
|
|
63
|
+
|
|
55
64
|
|
|
56
65
|
Discussion
|
|
57
66
|
----------
|
|
@@ -186,6 +195,8 @@ mail['from'] = 'mikel@test.lindsaar.net'
|
|
|
186
195
|
mail[:to] = 'you@test.lindsaar.net'
|
|
187
196
|
mail.subject = 'This is a test email'
|
|
188
197
|
|
|
198
|
+
mail.header['X-Custom-Header'] = 'custom value'
|
|
199
|
+
|
|
189
200
|
mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...
|
|
190
201
|
```
|
|
191
202
|
|
|
@@ -228,10 +239,10 @@ easy as:
|
|
|
228
239
|
|
|
229
240
|
```ruby
|
|
230
241
|
Mail.deliver do
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
242
|
+
from 'me@test.lindsaar.net'
|
|
243
|
+
to 'you@test.lindsaar.net'
|
|
244
|
+
subject 'Here is the image you wanted'
|
|
245
|
+
body File.read('body.txt')
|
|
235
246
|
add_file '/full/path/to/somefile.png'
|
|
236
247
|
end
|
|
237
248
|
```
|
|
@@ -266,6 +277,15 @@ mail.delivery_method :sendmail
|
|
|
266
277
|
mail.deliver
|
|
267
278
|
```
|
|
268
279
|
|
|
280
|
+
Sending via smtp (for example to [mailcatcher](https://github.com/sj26/mailcatcher))
|
|
281
|
+
```ruby
|
|
282
|
+
|
|
283
|
+
Mail.defaults do
|
|
284
|
+
delivery_method :smtp, address: "localhost", port: 1025
|
|
285
|
+
end
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
|
|
269
289
|
Exim requires its own delivery manager, and can be used like so:
|
|
270
290
|
|
|
271
291
|
```ruby
|
|
@@ -319,7 +339,7 @@ emails.length #=> LOTS!
|
|
|
319
339
|
```ruby
|
|
320
340
|
mail = Mail.read('/path/to/message.eml')
|
|
321
341
|
|
|
322
|
-
mail.
|
|
342
|
+
mail.envelope_from #=> 'mikel@test.lindsaar.net'
|
|
323
343
|
mail.from.addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
|
324
344
|
mail.sender.address #=> 'mikel@test.lindsaar.net'
|
|
325
345
|
mail.to #=> 'bob@test.lindsaar.net'
|
|
@@ -350,7 +370,7 @@ mail.parts[1].content_type_parameters #=> {'name' => 'my.pdf'}
|
|
|
350
370
|
Mail generates a tree of parts. Each message has many or no parts. Each part
|
|
351
371
|
is another message which can have many or no parts.
|
|
352
372
|
|
|
353
|
-
A message will only have parts if it is a multipart/mixed or related
|
|
373
|
+
A message will only have parts if it is a multipart/mixed or multipart/related
|
|
354
374
|
content type and has a boundary defined.
|
|
355
375
|
|
|
356
376
|
### Testing and extracting attachments
|
|
@@ -363,7 +383,7 @@ mail.attachments.each do | attachment |
|
|
|
363
383
|
filename = attachment.filename
|
|
364
384
|
begin
|
|
365
385
|
File.open(images_dir + filename, "w+b", 0644) {|f| f.write attachment.body.decoded}
|
|
366
|
-
rescue
|
|
386
|
+
rescue => e
|
|
367
387
|
puts "Unable to save data for #{filename} because #{e.message}"
|
|
368
388
|
end
|
|
369
389
|
end
|
|
@@ -546,7 +566,7 @@ Using Mail with Testing or Spec'ing Libraries
|
|
|
546
566
|
If mail is part of your system, you'll need a way to test it without actually
|
|
547
567
|
sending emails, the TestMailer can do this for you.
|
|
548
568
|
|
|
549
|
-
```
|
|
569
|
+
```ruby
|
|
550
570
|
require 'mail'
|
|
551
571
|
=> true
|
|
552
572
|
Mail.defaults do
|
|
@@ -572,7 +592,7 @@ Mail::TestMailer.deliveries.clear
|
|
|
572
592
|
|
|
573
593
|
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):
|
|
574
594
|
|
|
575
|
-
```
|
|
595
|
+
```ruby
|
|
576
596
|
Mail.defaults do
|
|
577
597
|
delivery_method :test # in practice you'd do this in spec_helper.rb
|
|
578
598
|
end
|
data/Rakefile
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
ENV[
|
|
1
|
+
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
|
|
2
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __FILE__)
|
|
3
|
+
end
|
|
2
4
|
require 'rubygems'
|
|
3
5
|
require 'bundler/setup'
|
|
4
6
|
|
|
@@ -17,5 +19,11 @@ RSpec::Core::RakeTask.new(:spec) do |t|
|
|
|
17
19
|
t.rspec_opts = %w(--backtrace --color)
|
|
18
20
|
end
|
|
19
21
|
|
|
22
|
+
begin
|
|
23
|
+
require "appraisal"
|
|
24
|
+
rescue LoadError
|
|
25
|
+
warn "Appraisal is only available in test/development"
|
|
26
|
+
end
|
|
27
|
+
|
|
20
28
|
# load custom rake tasks
|
|
21
|
-
Dir["#{File.dirname(__FILE__)}/
|
|
29
|
+
Dir["#{File.dirname(__FILE__)}/tasks/**/*.rake"].sort.each { |ext| load ext }
|
data/VERSION
ADDED
data/lib/mail/body.rb
CHANGED
|
@@ -127,9 +127,9 @@ module Mail
|
|
|
127
127
|
def sort_parts!
|
|
128
128
|
@parts.each do |p|
|
|
129
129
|
p.body.set_sort_order(@part_sort_order)
|
|
130
|
-
@parts.sort!(@part_sort_order)
|
|
131
130
|
p.body.sort_parts!
|
|
132
131
|
end
|
|
132
|
+
@parts.sort!(@part_sort_order)
|
|
133
133
|
end
|
|
134
134
|
|
|
135
135
|
# Returns the raw source that the body was initialized with, without
|
|
@@ -257,7 +257,7 @@ module Mail
|
|
|
257
257
|
|
|
258
258
|
def split!(boundary)
|
|
259
259
|
self.boundary = boundary
|
|
260
|
-
parts = raw_source.split(/(?:\A|\r\n)--#{Regexp.escape(boundary)}(?=(?:--)?\s*$)/)
|
|
260
|
+
parts = raw_source.split(/(?:\A|\r\n)--#{Regexp.escape(boundary || "")}(?=(?:--)?\s*$)/)
|
|
261
261
|
# Make the preamble equal to the preamble (if any)
|
|
262
262
|
self.preamble = parts[0].to_s.strip
|
|
263
263
|
# Make the epilogue equal to the epilogue (if any)
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
class String #:nodoc:
|
|
3
|
+
|
|
4
|
+
if RUBY_VERSION >= '1.9'
|
|
5
|
+
# This 1.9 only regex can save a reasonable amount of time (~20%)
|
|
6
|
+
# by not matching "\r\n" so the string is returned unchanged in
|
|
7
|
+
# the common case.
|
|
8
|
+
CRLF_REGEX = Regexp.new("(?<!\r)\n|\r(?!\n)")
|
|
9
|
+
else
|
|
10
|
+
CRLF_REGEX = /\n|\r\n|\r/
|
|
11
|
+
end
|
|
12
|
+
|
|
3
13
|
def to_crlf
|
|
4
|
-
to_str.gsub(
|
|
14
|
+
to_str.gsub(CRLF_REGEX, "\r\n")
|
|
5
15
|
end
|
|
6
16
|
|
|
7
17
|
def to_lf
|
|
8
|
-
to_str.gsub(/\
|
|
18
|
+
to_str.gsub(/\r\n|\r/, "\n")
|
|
9
19
|
end
|
|
10
20
|
|
|
11
21
|
unless String.instance_methods(false).map {|m| m.to_sym}.include?(:blank?)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
module Mail
|
|
3
3
|
class Address
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
# Mail::Address handles all email addresses in Mail. It takes an email address string
|
|
@@ -22,21 +22,19 @@ module Mail
|
|
|
22
22
|
# a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
|
23
23
|
def initialize(value = nil)
|
|
24
24
|
@output_type = :decode
|
|
25
|
-
|
|
26
|
-
@raw_text = value
|
|
27
|
-
case
|
|
28
|
-
when value.nil?
|
|
25
|
+
if value.nil?
|
|
29
26
|
@parsed = false
|
|
27
|
+
@data = nil
|
|
30
28
|
return
|
|
31
29
|
else
|
|
32
30
|
parse(value)
|
|
33
31
|
end
|
|
34
32
|
end
|
|
35
33
|
|
|
36
|
-
# Returns the raw
|
|
34
|
+
# Returns the raw input of the passed in string, this is before it is passed
|
|
37
35
|
# by the parser.
|
|
38
36
|
def raw
|
|
39
|
-
@
|
|
37
|
+
@data.raw
|
|
40
38
|
end
|
|
41
39
|
|
|
42
40
|
# Returns a correctly formatted address for the email going out. If given
|
|
@@ -48,15 +46,14 @@ module Mail
|
|
|
48
46
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
|
49
47
|
def format
|
|
50
48
|
parse unless @parsed
|
|
51
|
-
|
|
52
|
-
when tree.nil?
|
|
49
|
+
if @data.nil?
|
|
53
50
|
''
|
|
54
|
-
|
|
51
|
+
elsif display_name
|
|
55
52
|
[quote_phrase(display_name), "<#{address}>", format_comments].compact.join(" ")
|
|
56
|
-
|
|
53
|
+
elsif address
|
|
57
54
|
[address, format_comments].compact.join(" ")
|
|
58
55
|
else
|
|
59
|
-
|
|
56
|
+
raw
|
|
60
57
|
end
|
|
61
58
|
end
|
|
62
59
|
|
|
@@ -106,7 +103,7 @@ module Mail
|
|
|
106
103
|
# a.local #=> 'mikel'
|
|
107
104
|
def local
|
|
108
105
|
parse unless @parsed
|
|
109
|
-
"#{obs_domain_list}#{get_local.strip}" if get_local
|
|
106
|
+
"#{@data.obs_domain_list}#{get_local.strip}" if get_local
|
|
110
107
|
end
|
|
111
108
|
|
|
112
109
|
# Returns the domain part (the right hand side of the @ sign in the email address) of
|
|
@@ -174,29 +171,24 @@ module Mail
|
|
|
174
171
|
|
|
175
172
|
def parse(value = nil)
|
|
176
173
|
@parsed = true
|
|
177
|
-
|
|
178
|
-
|
|
174
|
+
|
|
175
|
+
case value
|
|
176
|
+
when NilClass
|
|
177
|
+
@data = nil
|
|
179
178
|
nil
|
|
180
|
-
when
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
179
|
+
when Mail::Parsers::AddressStruct
|
|
180
|
+
@data = value
|
|
181
|
+
when String
|
|
182
|
+
@raw_text = value
|
|
183
|
+
if value.blank?
|
|
184
|
+
@data = nil
|
|
185
|
+
else
|
|
186
|
+
address_list = Mail::Parsers::AddressListsParser.new.parse(value)
|
|
187
|
+
@data = address_list.addresses.first
|
|
188
|
+
end
|
|
184
189
|
end
|
|
185
190
|
end
|
|
186
191
|
|
|
187
|
-
|
|
188
|
-
def get_domain
|
|
189
|
-
if tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:domain)
|
|
190
|
-
@domain_text ||= tree.angle_addr.addr_spec.domain.text_value.strip
|
|
191
|
-
elsif tree.respond_to?(:domain)
|
|
192
|
-
@domain_text ||= tree.domain.text_value.strip
|
|
193
|
-
elsif tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:domain)
|
|
194
|
-
tree.addr_spec.domain.text_value.strip
|
|
195
|
-
else
|
|
196
|
-
nil
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
192
|
def strip_all_comments(string)
|
|
201
193
|
unless comments.blank?
|
|
202
194
|
comments.each do |comment|
|
|
@@ -209,7 +201,7 @@ module Mail
|
|
|
209
201
|
def strip_domain_comments(value)
|
|
210
202
|
unless comments.blank?
|
|
211
203
|
comments.each do |comment|
|
|
212
|
-
if
|
|
204
|
+
if @data.domain && @data.domain.include?("(#{comment})")
|
|
213
205
|
value = value.gsub("(#{comment})", '')
|
|
214
206
|
end
|
|
215
207
|
end
|
|
@@ -217,20 +209,11 @@ module Mail
|
|
|
217
209
|
value.to_s.strip
|
|
218
210
|
end
|
|
219
211
|
|
|
220
|
-
def get_comments
|
|
221
|
-
if tree.respond_to?(:comments)
|
|
222
|
-
@comments = tree.comments.map { |c| unparen(c.text_value.to_str) }
|
|
223
|
-
else
|
|
224
|
-
@comments = []
|
|
225
|
-
end
|
|
226
|
-
end
|
|
227
|
-
|
|
228
212
|
def get_display_name
|
|
229
|
-
if
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if domain
|
|
213
|
+
if @data.display_name
|
|
214
|
+
str = strip_all_comments(@data.display_name.to_s)
|
|
215
|
+
elsif @data.comments
|
|
216
|
+
if @data.domain
|
|
234
217
|
str = strip_domain_comments(format_comments)
|
|
235
218
|
else
|
|
236
219
|
str = nil
|
|
@@ -263,15 +246,6 @@ module Mail
|
|
|
263
246
|
end
|
|
264
247
|
end
|
|
265
248
|
|
|
266
|
-
# Provides access to the Treetop parse tree for this address
|
|
267
|
-
def tree
|
|
268
|
-
@tree
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
def tree=(value)
|
|
272
|
-
@tree = value
|
|
273
|
-
end
|
|
274
|
-
|
|
275
249
|
def format_comments
|
|
276
250
|
if comments
|
|
277
251
|
comment_text = comments.map {|c| escape_paren(c) }.join(' ').squeeze(" ")
|
|
@@ -280,35 +254,17 @@ module Mail
|
|
|
280
254
|
nil
|
|
281
255
|
end
|
|
282
256
|
end
|
|
283
|
-
|
|
284
|
-
def obs_domain_list
|
|
285
|
-
if tree.respond_to?(:angle_addr)
|
|
286
|
-
obs = tree.angle_addr.elements.select { |e| e.respond_to?(:obs_domain_list) }
|
|
287
|
-
!obs.empty? ? obs.first.text_value : nil
|
|
288
|
-
else
|
|
289
|
-
nil
|
|
290
|
-
end
|
|
291
|
-
end
|
|
292
|
-
|
|
257
|
+
|
|
293
258
|
def get_local
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
when tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:local_part)
|
|
300
|
-
tree.addr_spec.local_part.text_value
|
|
301
|
-
when tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:local_dot_atom_text)
|
|
302
|
-
# Ignore local dot atom text when in angle brackets
|
|
303
|
-
nil
|
|
304
|
-
when tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:local_dot_atom_text)
|
|
305
|
-
# Ignore local dot atom text when in angle brackets
|
|
306
|
-
nil
|
|
307
|
-
else
|
|
308
|
-
tree && tree.respond_to?(:local_part) ? tree.local_part.text_value : nil
|
|
309
|
-
end
|
|
259
|
+
@data && @data.local
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def get_domain
|
|
263
|
+
@data && @data.domain
|
|
310
264
|
end
|
|
311
265
|
|
|
312
|
-
|
|
266
|
+
def get_comments
|
|
267
|
+
@data && @data.comments
|
|
268
|
+
end
|
|
313
269
|
end
|
|
314
270
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
module Mail
|
|
3
3
|
class AddressList # :nodoc:
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
# Mail::AddressList is the class that parses To, From and other address fields from
|
|
6
6
|
# emails passed into Mail.
|
|
7
7
|
#
|
|
@@ -18,57 +18,34 @@ module Mail
|
|
|
18
18
|
# a.addresses #=> [#<Mail::Address:14943130 Address: |ada@test.lindsaar.net...
|
|
19
19
|
# a.group_names #=> ["My Group"]
|
|
20
20
|
def initialize(string)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return self
|
|
24
|
-
end
|
|
25
|
-
parser = Mail::AddressListsParser.new
|
|
26
|
-
if tree = parser.parse(string)
|
|
27
|
-
@address_nodes = tree.addresses
|
|
28
|
-
else
|
|
29
|
-
raise Mail::Field::ParseError.new(AddressListsParser, string, parser.failure_reason)
|
|
30
|
-
end
|
|
21
|
+
@addresses_grouped_by_group = nil
|
|
22
|
+
@address_list = Parsers::AddressListsParser.new.parse(string)
|
|
31
23
|
end
|
|
32
24
|
|
|
33
25
|
# Returns a list of address objects from the parsed line
|
|
34
26
|
def addresses
|
|
35
|
-
@addresses ||=
|
|
36
|
-
Mail::Address.new(
|
|
27
|
+
@addresses ||= @address_list.addresses.map do |address_data|
|
|
28
|
+
Mail::Address.new(address_data)
|
|
37
29
|
end
|
|
38
30
|
end
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
31
|
+
|
|
32
|
+
def addresses_grouped_by_group
|
|
33
|
+
return @addresses_grouped_by_group if @addresses_grouped_by_group
|
|
34
|
+
|
|
35
|
+
@addresses_grouped_by_group = {}
|
|
36
|
+
|
|
37
|
+
@address_list.addresses.each do |address_data|
|
|
38
|
+
if group = address_data.group
|
|
39
|
+
@addresses_grouped_by_group[group] ||= []
|
|
40
|
+
@addresses_grouped_by_group[group] << Mail::Address.new(address_data)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
@addresses_grouped_by_group
|
|
48
44
|
end
|
|
49
45
|
|
|
50
46
|
# Returns the names as an array of strings of all groups
|
|
51
47
|
def group_names # :nodoc:
|
|
52
|
-
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Returns a list of address syntax trees
|
|
56
|
-
def address_nodes # :nodoc:
|
|
57
|
-
@address_nodes
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
private
|
|
61
|
-
|
|
62
|
-
def get_addresses
|
|
63
|
-
(individual_recipients + group_recipients.map { |g| get_group_addresses(g) }).flatten
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def get_group_addresses(g)
|
|
67
|
-
if g.group_list.respond_to?(:addresses)
|
|
68
|
-
g.group_list.addresses
|
|
69
|
-
else
|
|
70
|
-
[]
|
|
71
|
-
end
|
|
48
|
+
@address_list.group_names
|
|
72
49
|
end
|
|
73
50
|
end
|
|
74
51
|
end
|
|
@@ -5,13 +5,9 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize( string )
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@parameters = tree.parameters
|
|
12
|
-
else
|
|
13
|
-
raise Mail::Field::ParseError.new(ContentDispositionElement, string, parser.failure_reason)
|
|
14
|
-
end
|
|
8
|
+
content_disposition = Mail::Parsers::ContentDispositionParser.new.parse(cleaned(string))
|
|
9
|
+
@disposition_type = content_disposition.disposition_type
|
|
10
|
+
@parameters = content_disposition.parameters
|
|
15
11
|
end
|
|
16
12
|
|
|
17
13
|
def disposition_type
|
|
@@ -5,12 +5,8 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize( string )
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@location = tree.location.text_value
|
|
11
|
-
else
|
|
12
|
-
raise Mail::Field::ParseError.new(ContentLocationElement, string, parser.failure_reason)
|
|
13
|
-
end
|
|
8
|
+
content_location = Mail::Parsers::ContentLocationParser.new.parse(string)
|
|
9
|
+
@location = content_location.location
|
|
14
10
|
end
|
|
15
11
|
|
|
16
12
|
def location
|
|
@@ -4,16 +4,9 @@ module Mail
|
|
|
4
4
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
|
-
def initialize(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
when string.blank?
|
|
11
|
-
@encoding = ''
|
|
12
|
-
when tree = parser.parse(string.to_s.downcase)
|
|
13
|
-
@encoding = tree.encoding.text_value
|
|
14
|
-
else
|
|
15
|
-
raise Mail::Field::ParseError.new(ContentTransferEncodingElement, string, parser.failure_reason)
|
|
16
|
-
end
|
|
7
|
+
def initialize(string)
|
|
8
|
+
content_transfer_encoding = Mail::Parsers::ContentTransferEncodingParser.new.parse(string)
|
|
9
|
+
@encoding = content_transfer_encoding.encoding
|
|
17
10
|
end
|
|
18
11
|
|
|
19
12
|
def encoding
|
|
@@ -5,14 +5,10 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize( string )
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@parameters = tree.parameters
|
|
13
|
-
else
|
|
14
|
-
raise Mail::Field::ParseError.new(ContentTypeElement, string, parser.failure_reason)
|
|
15
|
-
end
|
|
8
|
+
content_type = Mail::Parsers::ContentTypeParser.new.parse(cleaned(string))
|
|
9
|
+
@main_type = content_type.main_type
|
|
10
|
+
@sub_type = content_type.sub_type
|
|
11
|
+
@parameters = content_type.parameters
|
|
16
12
|
end
|
|
17
13
|
|
|
18
14
|
def main_type
|
|
@@ -5,13 +5,9 @@ module Mail
|
|
|
5
5
|
include Mail::Utilities
|
|
6
6
|
|
|
7
7
|
def initialize( string )
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@time_string = tree.time.text_value
|
|
12
|
-
else
|
|
13
|
-
raise Mail::Field::ParseError.new(DateTimeElement, string, parser.failure_reason)
|
|
14
|
-
end
|
|
8
|
+
date_time = Mail::Parsers::DateTimeParser.new.parse(string)
|
|
9
|
+
@date_string = date_time.date_string
|
|
10
|
+
@time_string = date_time.time_string
|
|
15
11
|
end
|
|
16
12
|
|
|
17
13
|
def date_string
|