mail 1.5.0 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mail might be problematic. Click here for more details.

data/Rakefile CHANGED
@@ -12,7 +12,7 @@ require 'bundler'
12
12
 
13
13
  spec = Gem::Specification.new do |s|
14
14
  s.name = "mail"
15
- s.version = "1.5.0"
15
+ s.version = "1.5.1"
16
16
  s.author = "Mike Lindsaar"
17
17
  s.email = "raasdnil@gmail.com"
18
18
  s.homepage = "http://github.com/mikel/mail"
@@ -47,10 +47,59 @@ module Mail
47
47
  include Patterns
48
48
  include Utilities
49
49
 
50
- # Creates a new Mail::Message object through .new
50
+ # ==Making an email
51
+ #
52
+ # You can make an new mail object via a block, passing a string, file or direct assignment.
53
+ #
54
+ # ===Making an email via a block
55
+ #
56
+ # mail = Mail.new do
57
+ # from 'mikel@test.lindsaar.net'
58
+ # to 'you@test.lindsaar.net'
59
+ # subject 'This is a test email'
60
+ # body File.read('body.txt')
61
+ # end
62
+ #
63
+ # mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...
64
+ #
65
+ # ===Making an email via passing a string
66
+ #
67
+ # mail = Mail.new("To: mikel@test.lindsaar.net\r\nSubject: Hello\r\n\r\nHi there!")
68
+ # mail.body.to_s #=> 'Hi there!'
69
+ # mail.subject #=> 'Hello'
70
+ # mail.to #=> 'mikel@test.lindsaar.net'
71
+ #
72
+ # ===Making an email from a file
73
+ #
74
+ # mail = Mail.read('path/to/file.eml')
75
+ # mail.body.to_s #=> 'Hi there!'
76
+ # mail.subject #=> 'Hello'
77
+ # mail.to #=> 'mikel@test.lindsaar.net'
78
+ #
79
+ # ===Making an email via assignment
80
+ #
81
+ # You can assign values to a mail object via four approaches:
82
+ #
83
+ # * Message#field_name=(value)
84
+ # * Message#field_name(value)
85
+ # * Message#['field_name']=(value)
86
+ # * Message#[:field_name]=(value)
87
+ #
88
+ # Examples:
89
+ #
90
+ # mail = Mail.new
91
+ # mail['from'] = 'mikel@test.lindsaar.net'
92
+ # mail[:to] = 'you@test.lindsaar.net'
93
+ # mail.subject 'This is a test email'
94
+ # mail.body = 'This is a body'
95
+ #
96
+ # mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...
97
+ #
51
98
  def initialize(*args, &block)
52
99
  @body = nil
53
-
100
+ @text_part = nil
101
+ @html_part = nil
102
+
54
103
  if args.flatten.first.respond_to?(:each_pair)
55
104
  init_with_hash(args.flatten.first)
56
105
  else
@@ -64,10 +113,30 @@ module Mail
64
113
  self
65
114
  end
66
115
 
116
+ # Delivers an mail object.
117
+ #
118
+ # Examples:
119
+ #
120
+ # mail = Mail.read('file.eml')
121
+ # mail.deliver!
67
122
  def deliver!
68
123
  Deliverable.perform_delivery!(self)
69
124
  end
70
125
 
126
+ # Provides the operator needed for sort et al.
127
+ #
128
+ # Compares this mail object with another mail object, this is done by date, so an
129
+ # email that is older than another will appear first.
130
+ #
131
+ # Example:
132
+ #
133
+ # mail1 = Mail.new do
134
+ # date(Time.now)
135
+ # end
136
+ # mail2 = Mail.new do
137
+ # date(Time.now - 86400) # 1 day older
138
+ # end
139
+ # [mail2, mail1].sort #=> [mail2, mail1]
71
140
  def <=>(other)
72
141
  if other.nil?
73
142
  1
@@ -76,11 +145,48 @@ module Mail
76
145
  end
77
146
  end
78
147
 
148
+ # Two emails are the same if they have the same fields and body contents. One
149
+ # gotcha here is that Mail will insert Message-IDs when calling encoded, so doing
150
+ # mail1.encoded == mail2.encoded is most probably not going to return what you think
151
+ # as the assigned Message-IDs by Mail (if not already defined as the same) will ensure
152
+ # that the two objects are unique, and this comparison will ALWAYS return false.
153
+ #
154
+ # So the == operator has been defined like so: Two messages are the same if they have
155
+ # the same content, ignoring the Message-ID field, unless BOTH emails have a defined and
156
+ # different Message-ID value, then they are false.
157
+ #
158
+ # So, in practice the == operator works like this:
159
+ #
160
+ # m1 = Mail.new("Subject: Hello\r\n\r\nHello")
161
+ # m2 = Mail.new("Subject: Hello\r\n\r\nHello")
162
+ # m1 == m2 #=> true
163
+ #
164
+ # m1 = Mail.new("Subject: Hello\r\n\r\nHello")
165
+ # m2 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
166
+ # m1 == m2 #=> true
167
+ #
168
+ # m1 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
169
+ # m2 = Mail.new("Subject: Hello\r\n\r\nHello")
170
+ # m1 == m2 #=> true
171
+ #
172
+ # m1 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
173
+ # m2 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
174
+ # m1 == m2 #=> true
175
+ #
176
+ # m1 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
177
+ # m2 = Mail.new("Message-ID: <DIFFERENT@test>\r\nSubject: Hello\r\n\r\nHello")
178
+ # m1 == m2 #=> false
79
179
  def ==(other)
80
- unless other.respond_to?(:encoded)
81
- false
180
+ return false unless other.respond_to?(:encoded)
181
+
182
+ if self.message_id && other.message_id
183
+ result = (self.encoded == other.encoded)
82
184
  else
83
- self.encoded == other.encoded
185
+ self_message_id, other_message_id = self.message_id, other.message_id
186
+ self.message_id, other.message_id = '<temp@test>', '<temp@test>'
187
+ result = self.encoded == other.encoded
188
+ self.message_id, other.message_id = "<#{self_message_id}>", "<#{other_message_id}>"
189
+ result
84
190
  end
85
191
  end
86
192
 
@@ -96,10 +202,7 @@ module Mail
96
202
  @raw_source
97
203
  end
98
204
 
99
- def raw_source=(value)
100
- @raw_source = value.to_crlf
101
- end
102
-
205
+ # Sets the envelope from for the email
103
206
  def set_envelope( val )
104
207
  @raw_envelope = val
105
208
  @envelope = Mail::Envelope.new( val )
@@ -1141,7 +1244,7 @@ module Mail
1141
1244
  def html_part(&block)
1142
1245
  if block_given?
1143
1246
  @html_part = Mail::Part.new(&block)
1144
- add_multipart_alternate_header
1247
+ add_multipart_alternate_header unless html_part.blank?
1145
1248
  add_part(@html_part)
1146
1249
  else
1147
1250
  @html_part
@@ -1152,7 +1255,7 @@ module Mail
1152
1255
  def text_part(&block)
1153
1256
  if block_given?
1154
1257
  @text_part = Mail::Part.new(&block)
1155
- add_multipart_alternate_header
1258
+ add_multipart_alternate_header unless html_part.blank?
1156
1259
  add_part(@text_part)
1157
1260
  else
1158
1261
  @text_part
@@ -1168,7 +1271,7 @@ module Mail
1168
1271
  else
1169
1272
  @html_part = Mail::Part.new('Content-Type: text/html;')
1170
1273
  end
1171
- add_multipart_alternate_header
1274
+ add_multipart_alternate_header unless text_part.blank?
1172
1275
  add_part(@html_part)
1173
1276
  end
1174
1277
 
@@ -1181,7 +1284,7 @@ module Mail
1181
1284
  else
1182
1285
  @text_part = Mail::Part.new('Content-Type: text/plain;')
1183
1286
  end
1184
- add_multipart_alternate_header
1287
+ add_multipart_alternate_header unless html_part.blank?
1185
1288
  add_part(@text_part)
1186
1289
  end
1187
1290
 
@@ -1330,6 +1433,10 @@ module Mail
1330
1433
  self.body = body_part
1331
1434
  end
1332
1435
 
1436
+ def raw_source=(value)
1437
+ @raw_source = value.to_crlf
1438
+ end
1439
+
1333
1440
  def set_envelope_header
1334
1441
  if match_data = raw_source.to_s.match(/^From\s(#{TEXT}+)#{CRLF}(.*)/m)
1335
1442
  set_envelope(match_data[1])
@@ -80,19 +80,24 @@ module Mail
80
80
  s5 << r6
81
81
  if r6
82
82
  if has_terminal?(";", false, index)
83
- r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
83
+ r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
84
84
  @index += 1
85
85
  else
86
86
  terminal_parse_failure(";")
87
- r7 = nil
87
+ r8 = nil
88
+ end
89
+ if r8
90
+ r7 = r8
91
+ else
92
+ r7 = instantiate_node(SyntaxNode,input, index...index)
88
93
  end
89
94
  s5 << r7
90
95
  if r7
91
- r8 = _nt_parameter
92
- s5 << r8
93
- if r8
94
- r9 = _nt_CFWS
95
- s5 << r9
96
+ r9 = _nt_parameter
97
+ s5 << r9
98
+ if r9
99
+ r10 = _nt_CFWS
100
+ s5 << r10
96
101
  end
97
102
  end
98
103
  end
@@ -5,7 +5,7 @@ module Mail
5
5
  include RFC2045
6
6
 
7
7
  rule content_type
8
- main_type "/" sub_type param_hashes:(CFWS ";" parameter CFWS)* {
8
+ main_type "/" sub_type param_hashes:(CFWS ";"? parameter CFWS)* {
9
9
  def parameters
10
10
  param_hashes.elements.map do |param|
11
11
  param.parameter.param_hash
@@ -2,7 +2,7 @@ module Arithmetic
2
2
  include Treetop::Runtime
3
3
 
4
4
  def root
5
- @root || :expression
5
+ @root ||= :expression
6
6
  end
7
7
 
8
8
  def _nt_expression
@@ -2,7 +2,7 @@ module LambdaCalculus
2
2
  include Treetop::Runtime
3
3
 
4
4
  def root
5
- @root || :program
5
+ @root ||= :program
6
6
  end
7
7
 
8
8
  include Arithmetic
@@ -7,7 +7,7 @@ module Treetop
7
7
  include Treetop::Runtime
8
8
 
9
9
  def root
10
- @root || :treetop_file
10
+ @root ||= :treetop_file
11
11
  end
12
12
 
13
13
  module TreetopFile0
@@ -3,7 +3,7 @@ module Mail
3
3
  module VERSION
4
4
  MAJOR = 1
5
5
  MINOR = 5
6
- TINY = 0
6
+ TINY = 1
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY].join('.')
9
9
  end
@@ -1,16 +1,17 @@
1
1
  namespace :corpus do
2
2
 
3
3
  task :load_mail do
4
+ $:.unshift File.expand_path('../', File.dirname(__FILE__))
4
5
  require 'lib/mail'
5
6
  end
6
7
 
7
8
  # Used to run parsing against an arbitrary corpus of email.
8
9
  # For example: http://plg.uwaterloo.ca/~gvcormac/treccorpus/
9
- desc "Provide a LOCATION=/some/dir to verify parsing in bulk"
10
+ desc "Provide a LOCATION=/some/dir to verify parsing in bulk, otherwise defaults"
10
11
  task :verify_all => :load_mail do
11
12
 
12
- root_of_corpus = ENV['LOCATION']
13
- @save_failures_to = ENV['SAVE_TO']
13
+ root_of_corpus = ENV['LOCATION'] || 'spec/fixtures/corpus/spam'
14
+ @save_failures_to = ENV['SAVE_TO'] || 'spec/fixtures/emails/failed_emails'
14
15
  @failed_emails = []
15
16
  @checked_count = 0
16
17
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mail
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Lindsaar
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-03 00:00:00 +11:00
12
+ date: 2010-01-04 00:00:00 +11:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency