dball-mail 2.2.9.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.
Files changed (122) hide show
  1. data/CHANGELOG.rdoc +459 -0
  2. data/README.rdoc +582 -0
  3. data/Rakefile +66 -0
  4. data/TODO.rdoc +9 -0
  5. data/lib/VERSION +4 -0
  6. data/lib/mail/attachments_list.rb +105 -0
  7. data/lib/mail/body.rb +286 -0
  8. data/lib/mail/configuration.rb +71 -0
  9. data/lib/mail/core_extensions/nil.rb +11 -0
  10. data/lib/mail/core_extensions/string.rb +27 -0
  11. data/lib/mail/elements/address.rb +306 -0
  12. data/lib/mail/elements/address_list.rb +74 -0
  13. data/lib/mail/elements/content_disposition_element.rb +30 -0
  14. data/lib/mail/elements/content_location_element.rb +25 -0
  15. data/lib/mail/elements/content_transfer_encoding_element.rb +24 -0
  16. data/lib/mail/elements/content_type_element.rb +35 -0
  17. data/lib/mail/elements/date_time_element.rb +26 -0
  18. data/lib/mail/elements/envelope_from_element.rb +34 -0
  19. data/lib/mail/elements/message_ids_element.rb +29 -0
  20. data/lib/mail/elements/mime_version_element.rb +26 -0
  21. data/lib/mail/elements/phrase_list.rb +21 -0
  22. data/lib/mail/elements/received_element.rb +30 -0
  23. data/lib/mail/elements.rb +14 -0
  24. data/lib/mail/encodings/7bit.rb +31 -0
  25. data/lib/mail/encodings/8bit.rb +31 -0
  26. data/lib/mail/encodings/base64.rb +33 -0
  27. data/lib/mail/encodings/binary.rb +31 -0
  28. data/lib/mail/encodings/quoted_printable.rb +38 -0
  29. data/lib/mail/encodings/transfer_encoding.rb +58 -0
  30. data/lib/mail/encodings.rb +268 -0
  31. data/lib/mail/envelope.rb +35 -0
  32. data/lib/mail/field.rb +223 -0
  33. data/lib/mail/field_list.rb +33 -0
  34. data/lib/mail/fields/bcc_field.rb +56 -0
  35. data/lib/mail/fields/cc_field.rb +55 -0
  36. data/lib/mail/fields/comments_field.rb +41 -0
  37. data/lib/mail/fields/common/address_container.rb +16 -0
  38. data/lib/mail/fields/common/common_address.rb +125 -0
  39. data/lib/mail/fields/common/common_date.rb +42 -0
  40. data/lib/mail/fields/common/common_field.rb +50 -0
  41. data/lib/mail/fields/common/common_message_id.rb +44 -0
  42. data/lib/mail/fields/common/parameter_hash.rb +58 -0
  43. data/lib/mail/fields/content_description_field.rb +19 -0
  44. data/lib/mail/fields/content_disposition_field.rb +69 -0
  45. data/lib/mail/fields/content_id_field.rb +63 -0
  46. data/lib/mail/fields/content_location_field.rb +42 -0
  47. data/lib/mail/fields/content_transfer_encoding_field.rb +50 -0
  48. data/lib/mail/fields/content_type_field.rb +198 -0
  49. data/lib/mail/fields/date_field.rb +55 -0
  50. data/lib/mail/fields/from_field.rb +55 -0
  51. data/lib/mail/fields/in_reply_to_field.rb +55 -0
  52. data/lib/mail/fields/keywords_field.rb +44 -0
  53. data/lib/mail/fields/message_id_field.rb +83 -0
  54. data/lib/mail/fields/mime_version_field.rb +53 -0
  55. data/lib/mail/fields/optional_field.rb +13 -0
  56. data/lib/mail/fields/received_field.rb +67 -0
  57. data/lib/mail/fields/references_field.rb +55 -0
  58. data/lib/mail/fields/reply_to_field.rb +55 -0
  59. data/lib/mail/fields/resent_bcc_field.rb +55 -0
  60. data/lib/mail/fields/resent_cc_field.rb +55 -0
  61. data/lib/mail/fields/resent_date_field.rb +35 -0
  62. data/lib/mail/fields/resent_from_field.rb +55 -0
  63. data/lib/mail/fields/resent_message_id_field.rb +34 -0
  64. data/lib/mail/fields/resent_sender_field.rb +62 -0
  65. data/lib/mail/fields/resent_to_field.rb +55 -0
  66. data/lib/mail/fields/return_path_field.rb +64 -0
  67. data/lib/mail/fields/sender_field.rb +67 -0
  68. data/lib/mail/fields/structured_field.rb +51 -0
  69. data/lib/mail/fields/subject_field.rb +16 -0
  70. data/lib/mail/fields/to_field.rb +55 -0
  71. data/lib/mail/fields/unstructured_field.rb +179 -0
  72. data/lib/mail/fields.rb +35 -0
  73. data/lib/mail/header.rb +264 -0
  74. data/lib/mail/mail.rb +255 -0
  75. data/lib/mail/message.rb +1972 -0
  76. data/lib/mail/network/delivery_methods/file_delivery.rb +40 -0
  77. data/lib/mail/network/delivery_methods/sendmail.rb +62 -0
  78. data/lib/mail/network/delivery_methods/smtp.rb +136 -0
  79. data/lib/mail/network/delivery_methods/test_mailer.rb +40 -0
  80. data/lib/mail/network/retriever_methods/imap.rb +213 -0
  81. data/lib/mail/network/retriever_methods/pop3.rb +194 -0
  82. data/lib/mail/network/retriever_methods/test_retriever.rb +31 -0
  83. data/lib/mail/network.rb +10 -0
  84. data/lib/mail/parsers/address_lists.rb +64 -0
  85. data/lib/mail/parsers/address_lists.treetop +19 -0
  86. data/lib/mail/parsers/content_disposition.rb +535 -0
  87. data/lib/mail/parsers/content_disposition.treetop +46 -0
  88. data/lib/mail/parsers/content_location.rb +139 -0
  89. data/lib/mail/parsers/content_location.treetop +20 -0
  90. data/lib/mail/parsers/content_transfer_encoding.rb +162 -0
  91. data/lib/mail/parsers/content_transfer_encoding.treetop +20 -0
  92. data/lib/mail/parsers/content_type.rb +967 -0
  93. data/lib/mail/parsers/content_type.treetop +68 -0
  94. data/lib/mail/parsers/date_time.rb +114 -0
  95. data/lib/mail/parsers/date_time.treetop +11 -0
  96. data/lib/mail/parsers/envelope_from.rb +194 -0
  97. data/lib/mail/parsers/envelope_from.treetop +32 -0
  98. data/lib/mail/parsers/message_ids.rb +45 -0
  99. data/lib/mail/parsers/message_ids.treetop +15 -0
  100. data/lib/mail/parsers/mime_version.rb +144 -0
  101. data/lib/mail/parsers/mime_version.treetop +19 -0
  102. data/lib/mail/parsers/phrase_lists.rb +45 -0
  103. data/lib/mail/parsers/phrase_lists.treetop +15 -0
  104. data/lib/mail/parsers/received.rb +71 -0
  105. data/lib/mail/parsers/received.treetop +11 -0
  106. data/lib/mail/parsers/rfc2045.rb +464 -0
  107. data/lib/mail/parsers/rfc2045.treetop +36 -0
  108. data/lib/mail/parsers/rfc2822.rb +5318 -0
  109. data/lib/mail/parsers/rfc2822.treetop +410 -0
  110. data/lib/mail/parsers/rfc2822_obsolete.rb +3757 -0
  111. data/lib/mail/parsers/rfc2822_obsolete.treetop +241 -0
  112. data/lib/mail/part.rb +116 -0
  113. data/lib/mail/parts_list.rb +43 -0
  114. data/lib/mail/patterns.rb +34 -0
  115. data/lib/mail/utilities.rb +211 -0
  116. data/lib/mail/version.rb +24 -0
  117. data/lib/mail/version_specific/ruby_1_8.rb +97 -0
  118. data/lib/mail/version_specific/ruby_1_9.rb +87 -0
  119. data/lib/mail.rb +80 -0
  120. data/lib/tasks/corpus.rake +125 -0
  121. data/lib/tasks/treetop.rake +10 -0
  122. metadata +255 -0
@@ -0,0 +1,1972 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ # The Message class provides a single point of access to all things to do with an
4
+ # email message.
5
+ #
6
+ # You create a new email message by calling the Mail::Message.new method, or just
7
+ # Mail.new
8
+ #
9
+ # A Message object by default has the following objects inside it:
10
+ #
11
+ # * A Header object which contians all information and settings of the header of the email
12
+ # * Body object which contains all parts of the email that are not part of the header, this
13
+ # includes any attachments, body text, MIME parts etc.
14
+ #
15
+ # ==Per RFC2822
16
+ #
17
+ # 2.1. General Description
18
+ #
19
+ # At the most basic level, a message is a series of characters. A
20
+ # message that is conformant with this standard is comprised of
21
+ # characters with values in the range 1 through 127 and interpreted as
22
+ # US-ASCII characters [ASCII]. For brevity, this document sometimes
23
+ # refers to this range of characters as simply "US-ASCII characters".
24
+ #
25
+ # Note: This standard specifies that messages are made up of characters
26
+ # in the US-ASCII range of 1 through 127. There are other documents,
27
+ # specifically the MIME document series [RFC2045, RFC2046, RFC2047,
28
+ # RFC2048, RFC2049], that extend this standard to allow for values
29
+ # outside of that range. Discussion of those mechanisms is not within
30
+ # the scope of this standard.
31
+ #
32
+ # Messages are divided into lines of characters. A line is a series of
33
+ # characters that is delimited with the two characters carriage-return
34
+ # and line-feed; that is, the carriage return (CR) character (ASCII
35
+ # value 13) followed immediately by the line feed (LF) character (ASCII
36
+ # value 10). (The carriage-return/line-feed pair is usually written in
37
+ # this document as "CRLF".)
38
+ #
39
+ # A message consists of header fields (collectively called "the header
40
+ # of the message") followed, optionally, by a body. The header is a
41
+ # sequence of lines of characters with special syntax as defined in
42
+ # this standard. The body is simply a sequence of characters that
43
+ # follows the header and is separated from the header by an empty line
44
+ # (i.e., a line with nothing preceding the CRLF).
45
+ class Message
46
+
47
+ include Patterns
48
+ include Utilities
49
+
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
+ #
98
+ def initialize(*args, &block)
99
+ @body = nil
100
+ @body_raw = nil
101
+ @body_raw_index = nil
102
+ @separate_parts = false
103
+ @text_part = nil
104
+ @html_part = nil
105
+ @errors = nil
106
+ @header = nil
107
+ @charset = 'UTF-8'
108
+ @defaulted_charset = true
109
+
110
+ @perform_deliveries = true
111
+ @raise_delivery_errors = true
112
+
113
+ @delivery_handler = nil
114
+
115
+ @delivery_method = Mail.delivery_method.dup
116
+
117
+ @transport_encoding = Mail::Encodings.get_encoding('7bit')
118
+
119
+ @mark_for_delete = false
120
+
121
+ if args.flatten.first.respond_to?(:each_pair)
122
+ init_with_hash(args.flatten.first)
123
+ else
124
+ init_with_string(args.flatten[0].to_s.strip)
125
+ end
126
+
127
+ if block_given?
128
+ instance_eval(&block)
129
+ end
130
+
131
+ self
132
+ end
133
+
134
+ # If you assign a delivery handler, mail will call :deliver_mail on the
135
+ # object you assign to delivery_handler, it will pass itself as the
136
+ # single argument.
137
+ #
138
+ # If you define a delivery_handler, then you are responsible for the
139
+ # following actions in the delivery cycle:
140
+ #
141
+ # * Appending the mail object to Mail.deliveries as you see fit.
142
+ # * Checking the mail.perform_deliveries flag to decide if you should
143
+ # actually call :deliver! the mail object or not.
144
+ # * Checking the mail.raise_delivery_errors flag to decide if you
145
+ # should raise delivery errors if they occur.
146
+ # * Actually calling :deliver! (with the bang) on the mail object to
147
+ # get it to deliver itself.
148
+ #
149
+ # A simplest implementation of a delivery_handler would be
150
+ #
151
+ # class MyObject
152
+ #
153
+ # def initialize
154
+ # @mail = Mail.new('To: mikel@test.lindsaar.net')
155
+ # @mail.delivery_handler = self
156
+ # end
157
+ #
158
+ # attr_accessor :mail
159
+ #
160
+ # def deliver_mail(mail)
161
+ # yield
162
+ # end
163
+ # end
164
+ #
165
+ # Then doing:
166
+ #
167
+ # obj = MyObject.new
168
+ # obj.mail.deliver
169
+ #
170
+ # Would cause Mail to call obj.deliver_mail passing itself as a parameter,
171
+ # which then can just yield and let Mail do it's own private do_delivery
172
+ # method.
173
+ attr_accessor :delivery_handler
174
+
175
+ # If set to false, mail will go through the motions of doing a delivery,
176
+ # but not actually call the delivery method or append the mail object to
177
+ # the Mail.deliveries collection. Useful for testing.
178
+ #
179
+ # Mail.deliveries.size #=> 0
180
+ # mail.delivery_method :smtp
181
+ # mail.perform_deliveries = false
182
+ # mail.deliver # Mail::SMTP not called here
183
+ # Mail.deliveries.size #=> 0
184
+ #
185
+ # If you want to test and query the Mail.deliveries collection to see what
186
+ # mail you sent, you should set perform_deliveries to true and use
187
+ # the :test mail delivery_method:
188
+ #
189
+ # Mail.deliveries.size #=> 0
190
+ # mail.delivery_method :test
191
+ # mail.perform_deliveries = true
192
+ # mail.deliver
193
+ # Mail.deliveries.size #=> 1
194
+ #
195
+ # This setting is ignored by mail (though still available as a flag) if you
196
+ # define a delivery_handler
197
+ attr_accessor :perform_deliveries
198
+
199
+ # If set to false, mail will silently catch and ignore any exceptions
200
+ # raised through attempting to deliver an email.
201
+ #
202
+ # This setting is ignored by mail (though still available as a flag) if you
203
+ # define a delivery_handler
204
+ attr_accessor :raise_delivery_errors
205
+
206
+ def register_for_delivery_notification(observer)
207
+ STDERR.puts("Message#register_for_delivery_notification is deprecated, please call Mail.register_observer instead")
208
+ Mail.register_observer(observer)
209
+ end
210
+
211
+ def inform_observers
212
+ Mail.inform_observers(self)
213
+ end
214
+
215
+ def inform_interceptors
216
+ Mail.inform_interceptors(self)
217
+ end
218
+
219
+ # Delivers an mail object.
220
+ #
221
+ # Examples:
222
+ #
223
+ # mail = Mail.read('file.eml')
224
+ # mail.deliver
225
+ def deliver
226
+ inform_interceptors
227
+ if delivery_handler
228
+ delivery_handler.deliver_mail(self) { do_delivery }
229
+ else
230
+ do_delivery
231
+ end
232
+ inform_observers
233
+ self
234
+ end
235
+
236
+ # This method bypasses checking perform_deliveries and raise_delivery_errors,
237
+ # so use with caution.
238
+ #
239
+ # It still however fires callbacks to the observers if they are defined.
240
+ #
241
+ # Returns self
242
+ def deliver!
243
+ delivery_method.deliver!(self)
244
+ inform_observers
245
+ self
246
+ end
247
+
248
+ def delivery_method(method = nil, settings = {})
249
+ unless method
250
+ @delivery_method
251
+ else
252
+ @delivery_method = Configuration.instance.lookup_delivery_method(method).new(settings)
253
+ end
254
+ end
255
+
256
+ def reply(*args, &block)
257
+ self.class.new.tap do |reply|
258
+ if message_id
259
+ bracketed_message_id = "<#{message_id}>"
260
+ reply.in_reply_to = bracketed_message_id
261
+ if !references.nil?
262
+ reply.references = (references.to_a.map { |r| "<#{r}>" } << bracketed_message_id).join(' ')
263
+ elsif !in_reply_to.nil? && !in_reply_to.kind_of?(Array)
264
+ reply.references = "<#{in_reply_to}> #{bracketed_message_id}"
265
+ end
266
+ reply.references ||= bracketed_message_id
267
+ end
268
+ if subject
269
+ reply.subject = "RE: #{subject}"
270
+ end
271
+ if reply_to || from
272
+ reply.to = self[reply_to ? :reply_to : :from].to_s
273
+ end
274
+ if to
275
+ reply.from = self[:to].formatted.first.to_s
276
+ end
277
+
278
+ unless args.empty?
279
+ if args.flatten.first.respond_to?(:each_pair)
280
+ reply.send(:init_with_hash, args.flatten.first)
281
+ else
282
+ reply.send(:init_with_string, args.flatten[0].to_s.strip)
283
+ end
284
+ end
285
+
286
+ if block_given?
287
+ reply.instance_eval(&block)
288
+ end
289
+ end
290
+ end
291
+
292
+ # Provides the operator needed for sort et al.
293
+ #
294
+ # Compares this mail object with another mail object, this is done by date, so an
295
+ # email that is older than another will appear first.
296
+ #
297
+ # Example:
298
+ #
299
+ # mail1 = Mail.new do
300
+ # date(Time.now)
301
+ # end
302
+ # mail2 = Mail.new do
303
+ # date(Time.now - 86400) # 1 day older
304
+ # end
305
+ # [mail2, mail1].sort #=> [mail2, mail1]
306
+ def <=>(other)
307
+ if other.nil?
308
+ 1
309
+ else
310
+ self.date <=> other.date
311
+ end
312
+ end
313
+
314
+ # Two emails are the same if they have the same fields and body contents. One
315
+ # gotcha here is that Mail will insert Message-IDs when calling encoded, so doing
316
+ # mail1.encoded == mail2.encoded is most probably not going to return what you think
317
+ # as the assigned Message-IDs by Mail (if not already defined as the same) will ensure
318
+ # that the two objects are unique, and this comparison will ALWAYS return false.
319
+ #
320
+ # So the == operator has been defined like so: Two messages are the same if they have
321
+ # the same content, ignoring the Message-ID field, unless BOTH emails have a defined and
322
+ # different Message-ID value, then they are false.
323
+ #
324
+ # So, in practice the == operator works like this:
325
+ #
326
+ # m1 = Mail.new("Subject: Hello\r\n\r\nHello")
327
+ # m2 = Mail.new("Subject: Hello\r\n\r\nHello")
328
+ # m1 == m2 #=> true
329
+ #
330
+ # m1 = Mail.new("Subject: Hello\r\n\r\nHello")
331
+ # m2 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
332
+ # m1 == m2 #=> true
333
+ #
334
+ # m1 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
335
+ # m2 = Mail.new("Subject: Hello\r\n\r\nHello")
336
+ # m1 == m2 #=> true
337
+ #
338
+ # m1 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
339
+ # m2 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
340
+ # m1 == m2 #=> true
341
+ #
342
+ # m1 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
343
+ # m2 = Mail.new("Message-ID: <DIFFERENT@test>\r\nSubject: Hello\r\n\r\nHello")
344
+ # m1 == m2 #=> false
345
+ def ==(other)
346
+ return false unless other.respond_to?(:encoded)
347
+
348
+ if self.message_id && other.message_id
349
+ result = (self.encoded == other.encoded)
350
+ else
351
+ self_message_id, other_message_id = self.message_id, other.message_id
352
+ self.message_id, other.message_id = '<temp@test>', '<temp@test>'
353
+ result = self.encoded == other.encoded
354
+ self.message_id = "<#{self_message_id}>" if self_message_id
355
+ other.message_id = "<#{other_message_id}>" if other_message_id
356
+ result
357
+ end
358
+ end
359
+
360
+ # Provides access to the raw source of the message as it was when it
361
+ # was instantiated. This is set at initialization and so is untouched
362
+ # by the parsers or decoder / encoders
363
+ #
364
+ # Example:
365
+ #
366
+ # mail = Mail.new('This is an invalid email message')
367
+ # mail.raw_source #=> "This is an invalid email message"
368
+ def raw_source
369
+ @raw_source
370
+ end
371
+
372
+ # Sets the envelope from for the email
373
+ def set_envelope( val )
374
+ @raw_envelope = val
375
+ @envelope = Mail::Envelope.new( val )
376
+ end
377
+
378
+ # The raw_envelope is the From mikel@test.lindsaar.net Mon May 2 16:07:05 2009
379
+ # type field that you can see at the top of any email that has come
380
+ # from a mailbox
381
+ def raw_envelope
382
+ @raw_envelope
383
+ end
384
+
385
+ def envelope_from
386
+ @envelope ? @envelope.from : nil
387
+ end
388
+
389
+ def envelope_date
390
+ @envelope ? @envelope.date : nil
391
+ end
392
+
393
+ # Sets the header of the message object.
394
+ #
395
+ # Example:
396
+ #
397
+ # mail.header = 'To: mikel@test.lindsaar.net\r\nFrom: Bob@bob.com'
398
+ # mail.header #=> <#Mail::Header
399
+ def header=(value)
400
+ @header = Mail::Header.new(value, charset)
401
+ end
402
+
403
+ # Returns the header object of the message object. Or, if passed
404
+ # a parameter sets the value.
405
+ #
406
+ # Example:
407
+ #
408
+ # mail = Mail::Message.new('To: mikel\r\nFrom: you')
409
+ # mail.header #=> #<Mail::Header:0x13ce14 @raw_source="To: mikel\r\nFr...
410
+ #
411
+ # mail.header #=> nil
412
+ # mail.header 'To: mikel\r\nFrom: you'
413
+ # mail.header #=> #<Mail::Header:0x13ce14 @raw_source="To: mikel\r\nFr...
414
+ def header(value = nil)
415
+ value ? self.header = value : @header
416
+ end
417
+
418
+ # Provides a way to set custom headers, by passing in a hash
419
+ def headers(hash = {})
420
+ hash.each_pair do |k,v|
421
+ header[k] = v
422
+ end
423
+ end
424
+
425
+ # Returns a list of parser errors on the header, each field that had an error
426
+ # will be reparsed as an unstructured field to preserve the data inside, but
427
+ # will not be used for further processing.
428
+ #
429
+ # It returns a nested array of [field_name, value, original_error_message]
430
+ # per error found.
431
+ #
432
+ # Example:
433
+ #
434
+ # message = Mail.new("Content-Transfer-Encoding: weirdo\r\n")
435
+ # message.errors.size #=> 1
436
+ # message.errors.first[0] #=> "Content-Transfer-Encoding"
437
+ # message.errors.first[1] #=> "weirdo"
438
+ # message.errors.first[3] #=> <The original error message exception>
439
+ #
440
+ # This is a good first defence on detecting spam by the way. Some spammers send
441
+ # invalid emails to try and get email parsers to give up parsing them.
442
+ def errors
443
+ header.errors
444
+ end
445
+
446
+ # Returns the Bcc value of the mail object as an array of strings of
447
+ # address specs.
448
+ #
449
+ # Example:
450
+ #
451
+ # mail.bcc = 'Mikel <mikel@test.lindsaar.net>'
452
+ # mail.bcc #=> ['mikel@test.lindsaar.net']
453
+ # mail.bcc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
454
+ # mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
455
+ #
456
+ # Also allows you to set the value by passing a value as a parameter
457
+ #
458
+ # Example:
459
+ #
460
+ # mail.bcc 'Mikel <mikel@test.lindsaar.net>'
461
+ # mail.bcc #=> ['mikel@test.lindsaar.net']
462
+ #
463
+ # Additionally, you can append new addresses to the returned Array like
464
+ # object.
465
+ #
466
+ # Example:
467
+ #
468
+ # mail.bcc 'Mikel <mikel@test.lindsaar.net>'
469
+ # mail.bcc << 'ada@test.lindsaar.net'
470
+ # mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
471
+ def bcc( val = nil )
472
+ default :bcc, val
473
+ end
474
+
475
+ # Sets the Bcc value of the mail object, pass in a string of the field
476
+ #
477
+ # Example:
478
+ #
479
+ # mail.bcc = 'Mikel <mikel@test.lindsaar.net>'
480
+ # mail.bcc #=> ['mikel@test.lindsaar.net']
481
+ # mail.bcc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
482
+ # mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
483
+ def bcc=( val )
484
+ header[:bcc] = val
485
+ end
486
+
487
+ # Returns the Cc value of the mail object as an array of strings of
488
+ # address specs.
489
+ #
490
+ # Example:
491
+ #
492
+ # mail.cc = 'Mikel <mikel@test.lindsaar.net>'
493
+ # mail.cc #=> ['mikel@test.lindsaar.net']
494
+ # mail.cc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
495
+ # mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
496
+ #
497
+ # Also allows you to set the value by passing a value as a parameter
498
+ #
499
+ # Example:
500
+ #
501
+ # mail.cc 'Mikel <mikel@test.lindsaar.net>'
502
+ # mail.cc #=> ['mikel@test.lindsaar.net']
503
+ #
504
+ # Additionally, you can append new addresses to the returned Array like
505
+ # object.
506
+ #
507
+ # Example:
508
+ #
509
+ # mail.cc 'Mikel <mikel@test.lindsaar.net>'
510
+ # mail.cc << 'ada@test.lindsaar.net'
511
+ # mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
512
+ def cc( val = nil )
513
+ default :cc, val
514
+ end
515
+
516
+ # Sets the Cc value of the mail object, pass in a string of the field
517
+ #
518
+ # Example:
519
+ #
520
+ # mail.cc = 'Mikel <mikel@test.lindsaar.net>'
521
+ # mail.cc #=> ['mikel@test.lindsaar.net']
522
+ # mail.cc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
523
+ # mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
524
+ def cc=( val )
525
+ header[:cc] = val
526
+ end
527
+
528
+ def comments( val = nil )
529
+ default :comments, val
530
+ end
531
+
532
+ def comments=( val )
533
+ header[:comments] = val
534
+ end
535
+
536
+ def content_description( val = nil )
537
+ default :content_description, val
538
+ end
539
+
540
+ def content_description=( val )
541
+ header[:content_description] = val
542
+ end
543
+
544
+ def content_disposition( val = nil )
545
+ default :content_disposition, val
546
+ end
547
+
548
+ def content_disposition=( val )
549
+ header[:content_disposition] = val
550
+ end
551
+
552
+ def content_id( val = nil )
553
+ default :content_id, val
554
+ end
555
+
556
+ def content_id=( val )
557
+ header[:content_id] = val
558
+ end
559
+
560
+ def content_location( val = nil )
561
+ default :content_location, val
562
+ end
563
+
564
+ def content_location=( val )
565
+ header[:content_location] = val
566
+ end
567
+
568
+ def content_transfer_encoding( val = nil )
569
+ default :content_transfer_encoding, val
570
+ end
571
+
572
+ def content_transfer_encoding=( val )
573
+ header[:content_transfer_encoding] = val
574
+ end
575
+
576
+ def content_type( val = nil )
577
+ default :content_type, val
578
+ end
579
+
580
+ def content_type=( val )
581
+ header[:content_type] = val
582
+ end
583
+
584
+ def date( val = nil )
585
+ default :date, val
586
+ end
587
+
588
+ def date=( val )
589
+ header[:date] = val
590
+ end
591
+
592
+ def transport_encoding( val = nil)
593
+ if val
594
+ self.transport_encoding = val
595
+ else
596
+ @transport_encoding
597
+ end
598
+ end
599
+
600
+ def transport_encoding=( val )
601
+ @transport_encoding = Mail::Encodings.get_encoding(val)
602
+ end
603
+
604
+ # Returns the From value of the mail object as an array of strings of
605
+ # address specs.
606
+ #
607
+ # Example:
608
+ #
609
+ # mail.from = 'Mikel <mikel@test.lindsaar.net>'
610
+ # mail.from #=> ['mikel@test.lindsaar.net']
611
+ # mail.from = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
612
+ # mail.from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
613
+ #
614
+ # Also allows you to set the value by passing a value as a parameter
615
+ #
616
+ # Example:
617
+ #
618
+ # mail.from 'Mikel <mikel@test.lindsaar.net>'
619
+ # mail.from #=> ['mikel@test.lindsaar.net']
620
+ #
621
+ # Additionally, you can append new addresses to the returned Array like
622
+ # object.
623
+ #
624
+ # Example:
625
+ #
626
+ # mail.from 'Mikel <mikel@test.lindsaar.net>'
627
+ # mail.from << 'ada@test.lindsaar.net'
628
+ # mail.from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
629
+ def from( val = nil )
630
+ default :from, val
631
+ end
632
+
633
+ # Sets the From value of the mail object, pass in a string of the field
634
+ #
635
+ # Example:
636
+ #
637
+ # mail.from = 'Mikel <mikel@test.lindsaar.net>'
638
+ # mail.from #=> ['mikel@test.lindsaar.net']
639
+ # mail.from = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
640
+ # mail.from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
641
+ def from=( val )
642
+ header[:from] = val
643
+ end
644
+
645
+ def in_reply_to( val = nil )
646
+ default :in_reply_to, val
647
+ end
648
+
649
+ def in_reply_to=( val )
650
+ header[:in_reply_to] = val
651
+ end
652
+
653
+ def keywords( val = nil )
654
+ default :keywords, val
655
+ end
656
+
657
+ def keywords=( val )
658
+ header[:keywords] = val
659
+ end
660
+
661
+ # Returns the Message-ID of the mail object. Note, per RFC 2822 the Message ID
662
+ # consists of what is INSIDE the < > usually seen in the mail header, so this method
663
+ # will return only what is inside.
664
+ #
665
+ # Example:
666
+ #
667
+ # mail.message_id = '<1234@message.id>'
668
+ # mail.message_id #=> '1234@message.id'
669
+ #
670
+ # Also allows you to set the Message-ID by passing a string as a parameter
671
+ #
672
+ # mail.message_id '<1234@message.id>'
673
+ # mail.message_id #=> '1234@message.id'
674
+ def message_id( val = nil )
675
+ default :message_id, val
676
+ end
677
+
678
+ # Sets the Message-ID. Note, per RFC 2822 the Message ID consists of what is INSIDE
679
+ # the < > usually seen in the mail header, so this method will return only what is inside.
680
+ #
681
+ # mail.message_id = '<1234@message.id>'
682
+ # mail.message_id #=> '1234@message.id'
683
+ def message_id=( val )
684
+ header[:message_id] = val
685
+ end
686
+
687
+ # Returns the MIME version of the email as a string
688
+ #
689
+ # Example:
690
+ #
691
+ # mail.mime_version = '1.0'
692
+ # mail.mime_version #=> '1.0'
693
+ #
694
+ # Also allows you to set the MIME version by passing a string as a parameter.
695
+ #
696
+ # Example:
697
+ #
698
+ # mail.mime_version '1.0'
699
+ # mail.mime_version #=> '1.0'
700
+ def mime_version( val = nil )
701
+ default :mime_version, val
702
+ end
703
+
704
+ # Sets the MIME version of the email by accepting a string
705
+ #
706
+ # Example:
707
+ #
708
+ # mail.mime_version = '1.0'
709
+ # mail.mime_version #=> '1.0'
710
+ def mime_version=( val )
711
+ header[:mime_version] = val
712
+ end
713
+
714
+ def received( val = nil )
715
+ if val
716
+ header[:received] = val
717
+ else
718
+ header[:received]
719
+ end
720
+ end
721
+
722
+ def received=( val )
723
+ header[:received] = val
724
+ end
725
+
726
+ def references( val = nil )
727
+ default :references, val
728
+ end
729
+
730
+ def references=( val )
731
+ header[:references] = val
732
+ end
733
+
734
+ # Returns the Reply-To value of the mail object as an array of strings of
735
+ # address specs.
736
+ #
737
+ # Example:
738
+ #
739
+ # mail.reply_to = 'Mikel <mikel@test.lindsaar.net>'
740
+ # mail.reply_to #=> ['mikel@test.lindsaar.net']
741
+ # mail.reply_to = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
742
+ # mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
743
+ #
744
+ # Also allows you to set the value by passing a value as a parameter
745
+ #
746
+ # Example:
747
+ #
748
+ # mail.reply_to 'Mikel <mikel@test.lindsaar.net>'
749
+ # mail.reply_to #=> ['mikel@test.lindsaar.net']
750
+ #
751
+ # Additionally, you can append new addresses to the returned Array like
752
+ # object.
753
+ #
754
+ # Example:
755
+ #
756
+ # mail.reply_to 'Mikel <mikel@test.lindsaar.net>'
757
+ # mail.reply_to << 'ada@test.lindsaar.net'
758
+ # mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
759
+ def reply_to( val = nil )
760
+ default :reply_to, val
761
+ end
762
+
763
+ # Sets the Reply-To value of the mail object, pass in a string of the field
764
+ #
765
+ # Example:
766
+ #
767
+ # mail.reply_to = 'Mikel <mikel@test.lindsaar.net>'
768
+ # mail.reply_to #=> ['mikel@test.lindsaar.net']
769
+ # mail.reply_to = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
770
+ # mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
771
+ def reply_to=( val )
772
+ header[:reply_to] = val
773
+ end
774
+
775
+ # Returns the Resent-Bcc value of the mail object as an array of strings of
776
+ # address specs.
777
+ #
778
+ # Example:
779
+ #
780
+ # mail.resent_bcc = 'Mikel <mikel@test.lindsaar.net>'
781
+ # mail.resent_bcc #=> ['mikel@test.lindsaar.net']
782
+ # mail.resent_bcc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
783
+ # mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
784
+ #
785
+ # Also allows you to set the value by passing a value as a parameter
786
+ #
787
+ # Example:
788
+ #
789
+ # mail.resent_bcc 'Mikel <mikel@test.lindsaar.net>'
790
+ # mail.resent_bcc #=> ['mikel@test.lindsaar.net']
791
+ #
792
+ # Additionally, you can append new addresses to the returned Array like
793
+ # object.
794
+ #
795
+ # Example:
796
+ #
797
+ # mail.resent_bcc 'Mikel <mikel@test.lindsaar.net>'
798
+ # mail.resent_bcc << 'ada@test.lindsaar.net'
799
+ # mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
800
+ def resent_bcc( val = nil )
801
+ default :resent_bcc, val
802
+ end
803
+
804
+ # Sets the Resent-Bcc value of the mail object, pass in a string of the field
805
+ #
806
+ # Example:
807
+ #
808
+ # mail.resent_bcc = 'Mikel <mikel@test.lindsaar.net>'
809
+ # mail.resent_bcc #=> ['mikel@test.lindsaar.net']
810
+ # mail.resent_bcc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
811
+ # mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
812
+ def resent_bcc=( val )
813
+ header[:resent_bcc] = val
814
+ end
815
+
816
+ # Returns the Resent-Cc value of the mail object as an array of strings of
817
+ # address specs.
818
+ #
819
+ # Example:
820
+ #
821
+ # mail.resent_cc = 'Mikel <mikel@test.lindsaar.net>'
822
+ # mail.resent_cc #=> ['mikel@test.lindsaar.net']
823
+ # mail.resent_cc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
824
+ # mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
825
+ #
826
+ # Also allows you to set the value by passing a value as a parameter
827
+ #
828
+ # Example:
829
+ #
830
+ # mail.resent_cc 'Mikel <mikel@test.lindsaar.net>'
831
+ # mail.resent_cc #=> ['mikel@test.lindsaar.net']
832
+ #
833
+ # Additionally, you can append new addresses to the returned Array like
834
+ # object.
835
+ #
836
+ # Example:
837
+ #
838
+ # mail.resent_cc 'Mikel <mikel@test.lindsaar.net>'
839
+ # mail.resent_cc << 'ada@test.lindsaar.net'
840
+ # mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
841
+ def resent_cc( val = nil )
842
+ default :resent_cc, val
843
+ end
844
+
845
+ # Sets the Resent-Cc value of the mail object, pass in a string of the field
846
+ #
847
+ # Example:
848
+ #
849
+ # mail.resent_cc = 'Mikel <mikel@test.lindsaar.net>'
850
+ # mail.resent_cc #=> ['mikel@test.lindsaar.net']
851
+ # mail.resent_cc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
852
+ # mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
853
+ def resent_cc=( val )
854
+ header[:resent_cc] = val
855
+ end
856
+
857
+ def resent_date( val = nil )
858
+ default :resent_date, val
859
+ end
860
+
861
+ def resent_date=( val )
862
+ header[:resent_date] = val
863
+ end
864
+
865
+ # Returns the Resent-From value of the mail object as an array of strings of
866
+ # address specs.
867
+ #
868
+ # Example:
869
+ #
870
+ # mail.resent_from = 'Mikel <mikel@test.lindsaar.net>'
871
+ # mail.resent_from #=> ['mikel@test.lindsaar.net']
872
+ # mail.resent_from = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
873
+ # mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
874
+ #
875
+ # Also allows you to set the value by passing a value as a parameter
876
+ #
877
+ # Example:
878
+ #
879
+ # mail.resent_from ['Mikel <mikel@test.lindsaar.net>']
880
+ # mail.resent_from #=> 'mikel@test.lindsaar.net'
881
+ #
882
+ # Additionally, you can append new addresses to the returned Array like
883
+ # object.
884
+ #
885
+ # Example:
886
+ #
887
+ # mail.resent_from 'Mikel <mikel@test.lindsaar.net>'
888
+ # mail.resent_from << 'ada@test.lindsaar.net'
889
+ # mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
890
+ def resent_from( val = nil )
891
+ default :resent_from, val
892
+ end
893
+
894
+ # Sets the Resent-From value of the mail object, pass in a string of the field
895
+ #
896
+ # Example:
897
+ #
898
+ # mail.resent_from = 'Mikel <mikel@test.lindsaar.net>'
899
+ # mail.resent_from #=> ['mikel@test.lindsaar.net']
900
+ # mail.resent_from = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
901
+ # mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
902
+ def resent_from=( val )
903
+ header[:resent_from] = val
904
+ end
905
+
906
+ def resent_message_id( val = nil )
907
+ default :resent_message_id, val
908
+ end
909
+
910
+ def resent_message_id=( val )
911
+ header[:resent_message_id] = val
912
+ end
913
+
914
+ # Returns the Resent-Sender value of the mail object, as a single string of an address
915
+ # spec. A sender per RFC 2822 must be a single address, so you can not append to
916
+ # this address.
917
+ #
918
+ # Example:
919
+ #
920
+ # mail.resent_sender = 'Mikel <mikel@test.lindsaar.net>'
921
+ # mail.resent_sender #=> 'mikel@test.lindsaar.net'
922
+ #
923
+ # Also allows you to set the value by passing a value as a parameter
924
+ #
925
+ # Example:
926
+ #
927
+ # mail.resent_sender 'Mikel <mikel@test.lindsaar.net>'
928
+ # mail.resent_sender #=> 'mikel@test.lindsaar.net'
929
+ def resent_sender( val = nil )
930
+ default :resent_sender, val
931
+ end
932
+
933
+ # Sets the Resent-Sender value of the mail object, pass in a string of the field
934
+ #
935
+ # Example:
936
+ #
937
+ # mail.sender = 'Mikel <mikel@test.lindsaar.net>'
938
+ # mail.sender #=> 'mikel@test.lindsaar.net'
939
+ def resent_sender=( val )
940
+ header[:resent_sender] = val
941
+ end
942
+
943
+ # Returns the Resent-To value of the mail object as an array of strings of
944
+ # address specs.
945
+ #
946
+ # Example:
947
+ #
948
+ # mail.resent_to = 'Mikel <mikel@test.lindsaar.net>'
949
+ # mail.resent_to #=> ['mikel@test.lindsaar.net']
950
+ # mail.resent_to = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
951
+ # mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
952
+ #
953
+ # Also allows you to set the value by passing a value as a parameter
954
+ #
955
+ # Example:
956
+ #
957
+ # mail.resent_to 'Mikel <mikel@test.lindsaar.net>'
958
+ # mail.resent_to #=> ['mikel@test.lindsaar.net']
959
+ #
960
+ # Additionally, you can append new addresses to the returned Array like
961
+ # object.
962
+ #
963
+ # Example:
964
+ #
965
+ # mail.resent_to 'Mikel <mikel@test.lindsaar.net>'
966
+ # mail.resent_to << 'ada@test.lindsaar.net'
967
+ # mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
968
+ def resent_to( val = nil )
969
+ default :resent_to, val
970
+ end
971
+
972
+ # Sets the Resent-To value of the mail object, pass in a string of the field
973
+ #
974
+ # Example:
975
+ #
976
+ # mail.resent_to = 'Mikel <mikel@test.lindsaar.net>'
977
+ # mail.resent_to #=> ['mikel@test.lindsaar.net']
978
+ # mail.resent_to = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
979
+ # mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
980
+ def resent_to=( val )
981
+ header[:resent_to] = val
982
+ end
983
+
984
+ # Returns the return path of the mail object, or sets it if you pass a string
985
+ def return_path( val = nil )
986
+ default :return_path, val
987
+ end
988
+
989
+ # Sets the return path of the object
990
+ def return_path=( val )
991
+ header[:return_path] = val
992
+ end
993
+
994
+ # Returns the Sender value of the mail object, as a single string of an address
995
+ # spec. A sender per RFC 2822 must be a single address.
996
+ #
997
+ # Example:
998
+ #
999
+ # mail.sender = 'Mikel <mikel@test.lindsaar.net>'
1000
+ # mail.sender #=> 'mikel@test.lindsaar.net'
1001
+ #
1002
+ # Also allows you to set the value by passing a value as a parameter
1003
+ #
1004
+ # Example:
1005
+ #
1006
+ # mail.sender 'Mikel <mikel@test.lindsaar.net>'
1007
+ # mail.sender #=> 'mikel@test.lindsaar.net'
1008
+ def sender( val = nil )
1009
+ default :sender, val
1010
+ end
1011
+
1012
+ # Sets the Sender value of the mail object, pass in a string of the field
1013
+ #
1014
+ # Example:
1015
+ #
1016
+ # mail.sender = 'Mikel <mikel@test.lindsaar.net>'
1017
+ # mail.sender #=> 'mikel@test.lindsaar.net'
1018
+ def sender=( val )
1019
+ header[:sender] = val
1020
+ end
1021
+
1022
+ # Returns the decoded value of the subject field, as a single string.
1023
+ #
1024
+ # Example:
1025
+ #
1026
+ # mail.subject = "G'Day mate"
1027
+ # mail.subject #=> "G'Day mate"
1028
+ # mail.subject = '=?UTF-8?Q?This_is_=E3=81=82_string?='
1029
+ # mail.subject #=> "This is あ string"
1030
+ #
1031
+ # Also allows you to set the value by passing a value as a parameter
1032
+ #
1033
+ # Example:
1034
+ #
1035
+ # mail.subject "G'Day mate"
1036
+ # mail.subject #=> "G'Day mate"
1037
+ def subject( val = nil )
1038
+ default :subject, val
1039
+ end
1040
+
1041
+ # Sets the Subject value of the mail object, pass in a string of the field
1042
+ #
1043
+ # Example:
1044
+ #
1045
+ # mail.subject = '=?UTF-8?Q?This_is_=E3=81=82_string?='
1046
+ # mail.subject #=> "This is あ string"
1047
+ def subject=( val )
1048
+ header[:subject] = val
1049
+ end
1050
+
1051
+ # Returns the To value of the mail object as an array of strings of
1052
+ # address specs.
1053
+ #
1054
+ # Example:
1055
+ #
1056
+ # mail.to = 'Mikel <mikel@test.lindsaar.net>'
1057
+ # mail.to #=> ['mikel@test.lindsaar.net']
1058
+ # mail.to = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
1059
+ # mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
1060
+ #
1061
+ # Also allows you to set the value by passing a value as a parameter
1062
+ #
1063
+ # Example:
1064
+ #
1065
+ # mail.to 'Mikel <mikel@test.lindsaar.net>'
1066
+ # mail.to #=> ['mikel@test.lindsaar.net']
1067
+ #
1068
+ # Additionally, you can append new addresses to the returned Array like
1069
+ # object.
1070
+ #
1071
+ # Example:
1072
+ #
1073
+ # mail.to 'Mikel <mikel@test.lindsaar.net>'
1074
+ # mail.to << 'ada@test.lindsaar.net'
1075
+ # mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
1076
+ def to( val = nil )
1077
+ default :to, val
1078
+ end
1079
+
1080
+ # Sets the To value of the mail object, pass in a string of the field
1081
+ #
1082
+ # Example:
1083
+ #
1084
+ # mail.to = 'Mikel <mikel@test.lindsaar.net>'
1085
+ # mail.to #=> ['mikel@test.lindsaar.net']
1086
+ # mail.to = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
1087
+ # mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
1088
+ def to=( val )
1089
+ header[:to] = val
1090
+ end
1091
+
1092
+ # Returns the default value of the field requested as a symbol.
1093
+ #
1094
+ # Each header field has a :default method which returns the most common use case for
1095
+ # that field, for example, the date field types will return a DateTime object when
1096
+ # sent :default, the subject, or unstructured fields will return a decoded string of
1097
+ # their value, the address field types will return a single addr_spec or an array of
1098
+ # addr_specs if there is more than one.
1099
+ def default( sym, val = nil )
1100
+ if val
1101
+ header[sym] = val
1102
+ else
1103
+ header[sym].default if header[sym]
1104
+ end
1105
+ end
1106
+
1107
+ # Sets the body object of the message object.
1108
+ #
1109
+ # Example:
1110
+ #
1111
+ # mail.body = 'This is the body'
1112
+ # mail.body #=> #<Mail::Body:0x13919c @raw_source="This is the bo...
1113
+ #
1114
+ # You can also reset the body of an Message object by setting body to nil
1115
+ #
1116
+ # Example:
1117
+ #
1118
+ # mail.body = 'this is the body'
1119
+ # mail.body.encoded #=> 'this is the body'
1120
+ # mail.body = nil
1121
+ # mail.body.encoded #=> ''
1122
+ #
1123
+ # If you try and set the body of an email that is a multipart email, then instead
1124
+ # of deleting all the parts of your email, mail will add a text/plain part to
1125
+ # your email:
1126
+ #
1127
+ # mail.add_file 'somefilename.png'
1128
+ # mail.parts.length #=> 1
1129
+ # mail.body = "This is a body"
1130
+ # mail.parts.length #=> 2
1131
+ # mail.parts.last.content_type.content_type #=> 'This is a body'
1132
+ def body=(value)
1133
+ body_lazy(value, 0)
1134
+ end
1135
+
1136
+ # Returns the body of the message object. Or, if passed
1137
+ # a parameter sets the value.
1138
+ #
1139
+ # Example:
1140
+ #
1141
+ # mail = Mail::Message.new('To: mikel\r\n\r\nThis is the body')
1142
+ # mail.body #=> #<Mail::Body:0x13919c @raw_source="This is the bo...
1143
+ #
1144
+ # mail.body 'This is another body'
1145
+ # mail.body #=> #<Mail::Body:0x13919c @raw_source="This is anothe...
1146
+ def body(value = nil)
1147
+ if value
1148
+ self.body = value
1149
+ # add_encoding_to_body
1150
+ else
1151
+ process_body_raw if @body_raw
1152
+ @body
1153
+ end
1154
+ end
1155
+
1156
+ def body_encoding(value)
1157
+ if value.nil?
1158
+ body.encoding
1159
+ else
1160
+ body.encoding = value
1161
+ end
1162
+ end
1163
+
1164
+ def body_encoding=(value)
1165
+ body.encoding = value
1166
+ end
1167
+
1168
+ # Returns the list of addresses this message should be sent to by
1169
+ # collecting the addresses off the to, cc and bcc fields.
1170
+ #
1171
+ # Example:
1172
+ #
1173
+ # mail.to = 'mikel@test.lindsaar.net'
1174
+ # mail.cc = 'sam@test.lindsaar.net'
1175
+ # mail.bcc = 'bob@test.lindsaar.net'
1176
+ # mail.destinations.length #=> 3
1177
+ # mail.destinations.first #=> 'mikel@test.lindsaar.net'
1178
+ def destinations
1179
+ [to_addrs, cc_addrs, bcc_addrs].compact.flatten
1180
+ end
1181
+
1182
+ # Returns an array of addresses (the encoded value) in the From field,
1183
+ # if no From field, returns an empty array
1184
+ def from_addrs
1185
+ from ? [from].flatten : []
1186
+ end
1187
+
1188
+ # Returns an array of addresses (the encoded value) in the To field,
1189
+ # if no To field, returns an empty array
1190
+ def to_addrs
1191
+ to ? [to].flatten : []
1192
+ end
1193
+
1194
+ # Returns an array of addresses (the encoded value) in the Cc field,
1195
+ # if no Cc field, returns an empty array
1196
+ def cc_addrs
1197
+ cc ? [cc].flatten : []
1198
+ end
1199
+
1200
+ # Returns an array of addresses (the encoded value) in the Bcc field,
1201
+ # if no Bcc field, returns an empty array
1202
+ def bcc_addrs
1203
+ bcc ? [bcc].flatten : []
1204
+ end
1205
+
1206
+ # Allows you to add an arbitrary header
1207
+ #
1208
+ # Example:
1209
+ #
1210
+ # mail['foo'] = '1234'
1211
+ # mail['foo'].to_s #=> '1234'
1212
+ def []=(name, value)
1213
+ if name.to_s == 'body'
1214
+ self.body = value
1215
+ elsif name.to_s =~ /content[-_]type/i
1216
+ header[name] = value
1217
+ elsif name.to_s == 'charset'
1218
+ self.charset = value
1219
+ else
1220
+ header[name] = value
1221
+ end
1222
+ end
1223
+
1224
+ # Allows you to read an arbitrary header
1225
+ #
1226
+ # Example:
1227
+ #
1228
+ # mail['foo'] = '1234'
1229
+ # mail['foo'].to_s #=> '1234'
1230
+ def [](name)
1231
+ header[underscoreize(name)]
1232
+ end
1233
+
1234
+ # Method Missing in this implementation allows you to set any of the
1235
+ # standard fields directly as you would the "to", "subject" etc.
1236
+ #
1237
+ # Those fields used most often (to, subject et al) are given their
1238
+ # own method for ease of documentation and also to avoid the hook
1239
+ # call to method missing.
1240
+ #
1241
+ # This will only catch the known fields listed in:
1242
+ #
1243
+ # Mail::Field::KNOWN_FIELDS
1244
+ #
1245
+ # as per RFC 2822, any ruby string or method name could pretty much
1246
+ # be a field name, so we don't want to just catch ANYTHING sent to
1247
+ # a message object and interpret it as a header.
1248
+ #
1249
+ # This method provides all three types of header call to set, read
1250
+ # and explicitly set with the = operator
1251
+ #
1252
+ # Examples:
1253
+ #
1254
+ # mail.comments = 'These are some comments'
1255
+ # mail.comments #=> 'These are some comments'
1256
+ #
1257
+ # mail.comments 'These are other comments'
1258
+ # mail.comments #=> 'These are other comments'
1259
+ #
1260
+ #
1261
+ # mail.date = 'Tue, 1 Jul 2003 10:52:37 +0200'
1262
+ # mail.date.to_s #=> 'Tue, 1 Jul 2003 10:52:37 +0200'
1263
+ #
1264
+ # mail.date 'Tue, 1 Jul 2003 10:52:37 +0200'
1265
+ # mail.date.to_s #=> 'Tue, 1 Jul 2003 10:52:37 +0200'
1266
+ #
1267
+ #
1268
+ # mail.resent_msg_id = '<1234@resent_msg_id.lindsaar.net>'
1269
+ # mail.resent_msg_id #=> '<1234@resent_msg_id.lindsaar.net>'
1270
+ #
1271
+ # mail.resent_msg_id '<4567@resent_msg_id.lindsaar.net>'
1272
+ # mail.resent_msg_id #=> '<4567@resent_msg_id.lindsaar.net>'
1273
+ def method_missing(name, *args, &block)
1274
+ #:nodoc:
1275
+ # Only take the structured fields, as we could take _anything_ really
1276
+ # as it could become an optional field... "but therin lies the dark side"
1277
+ field_name = underscoreize(name).chomp("=")
1278
+ if Mail::Field::KNOWN_FIELDS.include?(field_name)
1279
+ if args.empty?
1280
+ header[field_name]
1281
+ else
1282
+ header[field_name] = args.first
1283
+ end
1284
+ else
1285
+ super # otherwise pass it on
1286
+ end
1287
+ #:startdoc:
1288
+ end
1289
+
1290
+ # Returns an FieldList of all the fields in the header in the order that
1291
+ # they appear in the header
1292
+ def header_fields
1293
+ header.fields
1294
+ end
1295
+
1296
+ # Returns true if the message has a message ID field, the field may or may
1297
+ # not have a value, but the field exists or not.
1298
+ def has_message_id?
1299
+ header.has_message_id?
1300
+ end
1301
+
1302
+ # Returns true if the message has a Date field, the field may or may
1303
+ # not have a value, but the field exists or not.
1304
+ def has_date?
1305
+ header.has_date?
1306
+ end
1307
+
1308
+ # Returns true if the message has a Date field, the field may or may
1309
+ # not have a value, but the field exists or not.
1310
+ def has_mime_version?
1311
+ header.has_mime_version?
1312
+ end
1313
+
1314
+ def has_content_type?
1315
+ tmp = header[:content_type].main_type rescue nil
1316
+ !!tmp
1317
+ end
1318
+
1319
+ def has_charset?
1320
+ tmp = header[:content_type].parameters rescue nil
1321
+ !!(has_content_type? && tmp && tmp['charset'])
1322
+ end
1323
+
1324
+ def has_content_transfer_encoding?
1325
+ header[:content_transfer_encoding] && header[:content_transfer_encoding].errors.blank?
1326
+ end
1327
+
1328
+ def has_transfer_encoding? # :nodoc:
1329
+ STDERR.puts(":has_transfer_encoding? is deprecated in Mail 1.4.3. Please use has_content_transfer_encoding?\n#{caller}")
1330
+ has_content_transfer_encoding?
1331
+ end
1332
+
1333
+ # Creates a new empty Message-ID field and inserts it in the correct order
1334
+ # into the Header. The MessageIdField object will automatically generate
1335
+ # a unique message ID if you try and encode it or output it to_s without
1336
+ # specifying a message id.
1337
+ #
1338
+ # It will preserve the message ID you specify if you do.
1339
+ def add_message_id(msg_id_val = '')
1340
+ header['message-id'] = msg_id_val
1341
+ end
1342
+
1343
+ # Creates a new empty Date field and inserts it in the correct order
1344
+ # into the Header. The DateField object will automatically generate
1345
+ # DateTime.now's date if you try and encode it or output it to_s without
1346
+ # specifying a date yourself.
1347
+ #
1348
+ # It will preserve any date you specify if you do.
1349
+ def add_date(date_val = '')
1350
+ header['date'] = date_val
1351
+ end
1352
+
1353
+ # Creates a new empty Mime Version field and inserts it in the correct order
1354
+ # into the Header. The MimeVersion object will automatically generate
1355
+ # set itself to '1.0' if you try and encode it or output it to_s without
1356
+ # specifying a version yourself.
1357
+ #
1358
+ # It will preserve any date you specify if you do.
1359
+ def add_mime_version(ver_val = '')
1360
+ header['mime-version'] = ver_val
1361
+ end
1362
+
1363
+ # Adds a content type and charset if the body is US-ASCII
1364
+ #
1365
+ # Otherwise raises a warning
1366
+ def add_content_type
1367
+ header[:content_type] = 'text/plain'
1368
+ end
1369
+
1370
+ # Adds a content type and charset if the body is US-ASCII
1371
+ #
1372
+ # Otherwise raises a warning
1373
+ def add_charset
1374
+ if !body.empty?
1375
+ # Only give a warning if this isn't an attachment, has non US-ASCII and the user
1376
+ # has not specified an encoding explicitly.
1377
+ if @defaulted_charset && body.raw_source.not_ascii_only? && !self.attachment?
1378
+ warning = "Non US-ASCII detected and no charset defined.\nDefaulting to UTF-8, set your own if this is incorrect.\n"
1379
+ STDERR.puts(warning)
1380
+ end
1381
+ header[:content_type].parameters['charset'] = @charset
1382
+ end
1383
+ end
1384
+
1385
+ # Adds a content transfer encoding
1386
+ #
1387
+ # Otherwise raises a warning
1388
+ def add_content_transfer_encoding
1389
+ if body.only_us_ascii?
1390
+ header[:content_transfer_encoding] = '7bit'
1391
+ else
1392
+ warning = "Non US-ASCII detected and no content-transfer-encoding defined.\nDefaulting to 8bit, set your own if this is incorrect.\n"
1393
+ STDERR.puts(warning)
1394
+ header[:content_transfer_encoding] = '8bit'
1395
+ end
1396
+ end
1397
+
1398
+ def add_transfer_encoding # :nodoc:
1399
+ STDERR.puts(":add_transfer_encoding is deprecated in Mail 1.4.3. Please use add_content_transfer_encoding\n#{caller}")
1400
+ add_content_transfer_encoding
1401
+ end
1402
+
1403
+ def transfer_encoding # :nodoc:
1404
+ STDERR.puts(":transfer_encoding is deprecated in Mail 1.4.3. Please use content_transfer_encoding\n#{caller}")
1405
+ content_transfer_encoding
1406
+ end
1407
+
1408
+ # Returns the MIME media type of part we are on, this is taken from the content-type header
1409
+ def mime_type
1410
+ content_type ? header[:content_type].string : nil rescue nil
1411
+ end
1412
+
1413
+ def message_content_type
1414
+ STDERR.puts(":message_content_type is deprecated in Mail 1.4.3. Please use mime_type\n#{caller}")
1415
+ mime_type
1416
+ end
1417
+
1418
+ # Returns the character set defined in the content type field
1419
+ def charset
1420
+ if @header
1421
+ content_type ? content_type_parameters['charset'] : @charset
1422
+ else
1423
+ @charset
1424
+ end
1425
+ end
1426
+
1427
+ # Sets the charset to the supplied value.
1428
+ def charset=(value)
1429
+ @defaulted_charset = false
1430
+ @charset = value
1431
+ @header.charset = value
1432
+ end
1433
+
1434
+ # Returns the main content type
1435
+ def main_type
1436
+ has_content_type? ? header[:content_type].main_type : nil rescue nil
1437
+ end
1438
+
1439
+ # Returns the sub content type
1440
+ def sub_type
1441
+ has_content_type? ? header[:content_type].sub_type : nil rescue nil
1442
+ end
1443
+
1444
+ # Returns the content type parameters
1445
+ def mime_parameters
1446
+ STDERR.puts(':mime_parameters is deprecated in Mail 1.4.3, please use :content_type_parameters instead')
1447
+ content_type_parameters
1448
+ end
1449
+
1450
+ # Returns the content type parameters
1451
+ def content_type_parameters
1452
+ has_content_type? ? header[:content_type].parameters : nil rescue nil
1453
+ end
1454
+
1455
+ # Returns true if the message is multipart
1456
+ def multipart?
1457
+ has_content_type? ? !!(main_type =~ /^multipart$/i) : false
1458
+ end
1459
+
1460
+ # Returns true if the message is a multipart/report
1461
+ def multipart_report?
1462
+ multipart? && sub_type =~ /^report$/i
1463
+ end
1464
+
1465
+ # Returns true if the message is a multipart/report; report-type=delivery-status;
1466
+ def delivery_status_report?
1467
+ multipart_report? && content_type_parameters['report-type'] =~ /^delivery-status$/i
1468
+ end
1469
+
1470
+ # returns the part in a multipart/report email that has the content-type delivery-status
1471
+ def delivery_status_part
1472
+ @delivery_stats_part ||= parts.select { |p| p.delivery_status_report_part? }.first
1473
+ end
1474
+
1475
+ def bounced?
1476
+ delivery_status_part and delivery_status_part.bounced?
1477
+ end
1478
+
1479
+ def action
1480
+ delivery_status_part and delivery_status_part.action
1481
+ end
1482
+
1483
+ def final_recipient
1484
+ delivery_status_part and delivery_status_part.final_recipient
1485
+ end
1486
+
1487
+ def error_status
1488
+ delivery_status_part and delivery_status_part.error_status
1489
+ end
1490
+
1491
+ def diagnostic_code
1492
+ delivery_status_part and delivery_status_part.diagnostic_code
1493
+ end
1494
+
1495
+ def remote_mta
1496
+ delivery_status_part and delivery_status_part.remote_mta
1497
+ end
1498
+
1499
+ def retryable?
1500
+ delivery_status_part and delivery_status_part.retryable?
1501
+ end
1502
+
1503
+ # Returns the current boundary for this message part
1504
+ def boundary
1505
+ content_type_parameters ? content_type_parameters['boundary'] : nil
1506
+ end
1507
+
1508
+ # Returns a parts list object of all the parts in the message
1509
+ def parts
1510
+ body.parts
1511
+ end
1512
+
1513
+ # Returns an AttachmentsList object, which holds all of the attachments in
1514
+ # the receiver object (either the entier email or a part within) and all
1515
+ # of it's descendants.
1516
+ #
1517
+ # It also allows you to add attachments to the mail object directly, like so:
1518
+ #
1519
+ # mail.attachments['filename.jpg'] = File.read('/path/to/filename.jpg')
1520
+ #
1521
+ # If you do this, then Mail will take the file name and work out the MIME media type
1522
+ # set the Content-Type, Content-Disposition, Content-Transfer-Encoding and
1523
+ # base64 encode the contents of the attachment all for you.
1524
+ #
1525
+ # You can also specify overrides if you want by passing a hash instead of a string:
1526
+ #
1527
+ # mail.attachments['filename.jpg'] = {:mime_type => 'application/x-gzip',
1528
+ # :content => File.read('/path/to/filename.jpg')}
1529
+ #
1530
+ # If you want to use a different encoding than Base64, you can pass an encoding in,
1531
+ # but then it is up to you to pass in the content pre-encoded, and don't expect
1532
+ # Mail to know how to decode this data:
1533
+ #
1534
+ # file_content = SpecialEncode(File.read('/path/to/filename.jpg'))
1535
+ # mail.attachments['filename.jpg'] = {:mime_type => 'application/x-gzip',
1536
+ # :encoding => 'SpecialEncoding',
1537
+ # :content => file_content }
1538
+ #
1539
+ # You can also search for specific attachments:
1540
+ #
1541
+ # # By Filename
1542
+ # mail.attachments['filename.jpg'] #=> Mail::Part object or nil
1543
+ #
1544
+ # # or by index
1545
+ # mail.attachments[0] #=> Mail::Part (first attachment)
1546
+ #
1547
+ def attachments
1548
+ parts.attachments
1549
+ end
1550
+
1551
+ def has_attachments?
1552
+ !attachments.empty?
1553
+ end
1554
+
1555
+ # Accessor for html_part
1556
+ def html_part(&block)
1557
+ if block_given?
1558
+ @html_part = Mail::Part.new(&block)
1559
+ add_multipart_alternate_header unless html_part.blank?
1560
+ add_part(@html_part)
1561
+ else
1562
+ @html_part || find_first_mime_type('text/html')
1563
+ end
1564
+ end
1565
+
1566
+ # Accessor for text_part
1567
+ def text_part(&block)
1568
+ if block_given?
1569
+ @text_part = Mail::Part.new(&block)
1570
+ add_multipart_alternate_header unless html_part.blank?
1571
+ add_part(@text_part)
1572
+ else
1573
+ @text_part || find_first_mime_type('text/plain')
1574
+ end
1575
+ end
1576
+
1577
+ # Helper to add a html part to a multipart/alternative email. If this and
1578
+ # text_part are both defined in a message, then it will be a multipart/alternative
1579
+ # message and set itself that way.
1580
+ def html_part=(msg = nil)
1581
+ if msg
1582
+ @html_part = msg
1583
+ else
1584
+ @html_part = Mail::Part.new('Content-Type: text/html;')
1585
+ end
1586
+ add_multipart_alternate_header unless text_part.blank?
1587
+ add_part(@html_part)
1588
+ end
1589
+
1590
+ # Helper to add a text part to a multipart/alternative email. If this and
1591
+ # html_part are both defined in a message, then it will be a multipart/alternative
1592
+ # message and set itself that way.
1593
+ def text_part=(msg = nil)
1594
+ if msg
1595
+ @text_part = msg
1596
+ else
1597
+ @text_part = Mail::Part.new('Content-Type: text/plain;')
1598
+ end
1599
+ add_multipart_alternate_header unless html_part.blank?
1600
+ add_part(@text_part)
1601
+ end
1602
+
1603
+ # Adds a part to the parts list or creates the part list
1604
+ def add_part(part)
1605
+ if !body.multipart? && !self.body.decoded.blank?
1606
+ @text_part = Mail::Part.new('Content-Type: text/plain;')
1607
+ @text_part.body = body.decoded
1608
+ self.body << @text_part
1609
+ add_multipart_alternate_header
1610
+ end
1611
+ add_boundary
1612
+ self.body << part
1613
+ end
1614
+
1615
+ # Allows you to add a part in block form to an existing mail message object
1616
+ #
1617
+ # Example:
1618
+ #
1619
+ # mail = Mail.new do
1620
+ # part :content_type => "multipart/alternative", :content_disposition => "inline" do |p|
1621
+ # p.part :content_type => "text/plain", :body => "test text\nline #2"
1622
+ # p.part :content_type => "text/html", :body => "<b>test</b> HTML<br/>\nline #2"
1623
+ # end
1624
+ # end
1625
+ def part(params = {})
1626
+ new_part = Part.new(params)
1627
+ yield new_part if block_given?
1628
+ add_part(new_part)
1629
+ end
1630
+
1631
+ # Adds a file to the message. You have two options with this method, you can
1632
+ # just pass in the absolute path to the file you want and Mail will read the file,
1633
+ # get the filename from the path you pass in and guess the MIME media type, or you
1634
+ # can pass in the filename as a string, and pass in the file content as a blob.
1635
+ #
1636
+ # Example:
1637
+ #
1638
+ # m = Mail.new
1639
+ # m.add_file('/path/to/filename.png')
1640
+ #
1641
+ # m = Mail.new
1642
+ # m.add_file(:filename => 'filename.png', :content => File.read('/path/to/file.jpg'))
1643
+ #
1644
+ # Note also that if you add a file to an existing message, Mail will convert that message
1645
+ # to a MIME multipart email, moving whatever plain text body you had into it's own text
1646
+ # plain part.
1647
+ #
1648
+ # Example:
1649
+ #
1650
+ # m = Mail.new do
1651
+ # body 'this is some text'
1652
+ # end
1653
+ # m.multipart? #=> false
1654
+ # m.add_file('/path/to/filename.png')
1655
+ # m.multipart? #=> true
1656
+ # m.parts.first.content_type.content_type #=> 'text/plain'
1657
+ # m.parts.last.content_type.content_type #=> 'image/png'
1658
+ #
1659
+ # See also #attachments
1660
+ def add_file(values)
1661
+ convert_to_multipart unless self.multipart? || self.body.decoded.blank?
1662
+ add_multipart_mixed_header
1663
+ if values.is_a?(String)
1664
+ basename = File.basename(values)
1665
+ filedata = File.open(values, 'rb') { |f| f.read }
1666
+ else
1667
+ basename = values[:filename]
1668
+ filedata = values[:content] || File.open(values[:filename], 'rb') { |f| f.read }
1669
+ end
1670
+ self.attachments[basename] = filedata
1671
+ end
1672
+
1673
+ def convert_to_multipart
1674
+ text = body.decoded
1675
+ self.body = ''
1676
+ text_part = Mail::Part.new({:content_type => 'text/plain;',
1677
+ :body => text})
1678
+ self.body << text_part
1679
+ end
1680
+
1681
+ # Encodes the message, calls encode on all it's parts, gets an email message
1682
+ # ready to send
1683
+ def ready_to_send!
1684
+ identify_and_set_transfer_encoding
1685
+ parts.sort!([ "text/plain", "text/enriched", "text/html", "multipart/alternative" ])
1686
+ parts.each do |part|
1687
+ part.transport_encoding = transport_encoding
1688
+ part.ready_to_send!
1689
+ end
1690
+ add_required_fields
1691
+ end
1692
+
1693
+ def encode!
1694
+ STDERR.puts("Deprecated in 1.1.0 in favour of :ready_to_send! as it is less confusing with encoding and decoding.")
1695
+ ready_to_send!
1696
+ end
1697
+
1698
+ # Outputs an encoded string representation of the mail message including
1699
+ # all headers, attachments, etc. This is an encoded email in US-ASCII,
1700
+ # so it is able to be directly sent to an email server.
1701
+ def encoded
1702
+ ready_to_send!
1703
+ buffer = header.encoded
1704
+ buffer << "\r\n"
1705
+ buffer << body.encoded(content_transfer_encoding)
1706
+ buffer
1707
+ end
1708
+
1709
+ def to_s
1710
+ encoded
1711
+ end
1712
+
1713
+ def inspect
1714
+ "#<#{self.class}:#{self.object_id}, Multipart: #{multipart?}, Headers: #{header.field_summary}>"
1715
+ end
1716
+
1717
+ def decoded
1718
+ case
1719
+ when self.attachment?
1720
+ decode_body
1721
+ when !self.multipart?
1722
+ body.decoded
1723
+ else
1724
+ raise NoMethodError, 'Can not decode an entire message, try calling #decoded on the various fields and body or parts if it is a multipart message.'
1725
+ end
1726
+ end
1727
+
1728
+ def read
1729
+ if self.attachment?
1730
+ decode_body
1731
+ else
1732
+ raise NoMethodError, 'Can not call read on a part unless it is an attachment.'
1733
+ end
1734
+ end
1735
+
1736
+ def decode_body
1737
+ body.decoded
1738
+ end
1739
+
1740
+ # Returns true if this part is an attachment,
1741
+ # false otherwise.
1742
+ def attachment?
1743
+ !!find_attachment
1744
+ end
1745
+
1746
+ # Returns the attachment data if there is any
1747
+ def attachment
1748
+ @attachment
1749
+ end
1750
+
1751
+ # Returns the filename of the attachment
1752
+ def filename
1753
+ find_attachment
1754
+ end
1755
+
1756
+ def all_parts
1757
+ parts.map { |p| [p, p.all_parts] }.flatten
1758
+ end
1759
+
1760
+ def find_first_mime_type(mt)
1761
+ all_parts.detect { |p| p.mime_type == mt }
1762
+ end
1763
+
1764
+ # Skips the deletion of this message. All other messages
1765
+ # flagged for delete still will be deleted at session close (i.e. when
1766
+ # #find exits). Only has an effect if you're using #find_and_delete
1767
+ # or #find with :delete_after_find set to true.
1768
+ def skip_deletion
1769
+ @mark_for_delete = false
1770
+ end
1771
+
1772
+ # Sets whether this message should be deleted at session close (i.e.
1773
+ # after #find). Message will only be deleted if messages are retrieved
1774
+ # using the #find_and_delete method, or by calling #find with
1775
+ # :delete_after_find set to true.
1776
+ def mark_for_delete=(value = true)
1777
+ @mark_for_delete = value
1778
+ end
1779
+
1780
+ # Returns whether message will be marked for deletion.
1781
+ # If so, the message will be deleted at session close (i.e. after #find
1782
+ # exits), but only if also using the #find_and_delete method, or by
1783
+ # calling #find with :delete_after_find set to true.
1784
+ #
1785
+ # Side-note: Just to be clear, this method will return true even if
1786
+ # the message hasn't yet been marked for delete on the mail server.
1787
+ # However, if this method returns true, it *will be* marked on the
1788
+ # server after each block yields back to #find or #find_and_delete.
1789
+ def is_marked_for_delete?
1790
+ return @mark_for_delete
1791
+ end
1792
+
1793
+ private
1794
+
1795
+ # 2.1. General Description
1796
+ # A message consists of header fields (collectively called "the header
1797
+ # of the message") followed, optionally, by a body. The header is a
1798
+ # sequence of lines of characters with special syntax as defined in
1799
+ # this standard. The body is simply a sequence of characters that
1800
+ # follows the header and is separated from the header by an empty line
1801
+ # (i.e., a line with nothing preceding the CRLF).
1802
+ #
1803
+ # Additionally, I allow for the case where someone might have put whitespace
1804
+ # on the "gap line"
1805
+ def parse_message
1806
+ header_part, body_part = raw_source.split(/#{CRLF}#{WSP}*#{CRLF}/m, 2)
1807
+ # index = raw_source.index(/#{CRLF}#{WSP}*#{CRLF}/m, 2)
1808
+ # self.header = (index) ? header_part[0,index] : nil
1809
+ # lazy_body ( [raw_source, index+1])
1810
+ self.header = header_part
1811
+ self.body = body_part
1812
+ end
1813
+
1814
+ def raw_source=(value)
1815
+ @raw_source = value.to_crlf
1816
+ end
1817
+
1818
+ # see comments to body=. We take data starting from index and process it lazily
1819
+ def body_lazy(value, index)
1820
+ process_body_raw if @body_raw && value
1821
+ case
1822
+ when value == nil || value.length<=index
1823
+ @body = Mail::Body.new('')
1824
+ @body_raw = nil
1825
+ @body_raw_index = nil
1826
+ add_encoding_to_body
1827
+ when @body && @body.multipart?
1828
+ @body << Mail::Part.new(value[index, value.length-index])
1829
+ add_encoding_to_body
1830
+ else
1831
+ @body_raw = value
1832
+ @body_raw_index = index
1833
+ # process_body_raw
1834
+ end
1835
+ end
1836
+
1837
+
1838
+ def process_body_raw
1839
+ @body = Mail::Body.new(@body_raw[@body_raw_index, @body_raw.length-@body_raw_index])
1840
+ @body_raw = nil
1841
+ @body_raw_index = nil
1842
+ separate_parts if @separate_parts
1843
+
1844
+ add_encoding_to_body
1845
+ end
1846
+
1847
+ def set_envelope_header
1848
+ if match_data = raw_source.to_s.match(/\AFrom\s(#{TEXT}+)#{CRLF}(.*)/m)
1849
+ set_envelope(match_data[1])
1850
+ self.raw_source = match_data[2]
1851
+ end
1852
+ end
1853
+
1854
+ def separate_parts
1855
+ body.split!(boundary)
1856
+ end
1857
+
1858
+ def add_encoding_to_body
1859
+ if has_content_transfer_encoding?
1860
+ @body.encoding = content_transfer_encoding
1861
+ end
1862
+ end
1863
+
1864
+ def identify_and_set_transfer_encoding
1865
+ if body && body.multipart?
1866
+ self.content_transfer_encoding = @transport_encoding
1867
+ else
1868
+ self.content_transfer_encoding = body.get_best_encoding(@transport_encoding)
1869
+ end
1870
+ end
1871
+
1872
+ def add_required_fields
1873
+ add_multipart_mixed_header unless !body.multipart?
1874
+ body = nil if body.nil?
1875
+ add_message_id unless (has_message_id? || self.class == Mail::Part)
1876
+ add_date unless has_date?
1877
+ add_mime_version unless has_mime_version?
1878
+ add_content_type unless has_content_type?
1879
+ add_charset unless has_charset?
1880
+ add_content_transfer_encoding unless has_content_transfer_encoding?
1881
+ end
1882
+
1883
+ def add_multipart_alternate_header
1884
+ header['content-type'] = ContentTypeField.with_boundary('multipart/alternative').value
1885
+ header['content_type'].parameters[:charset] = @charset
1886
+ body.boundary = boundary
1887
+ end
1888
+
1889
+ def add_boundary
1890
+ unless body.boundary && boundary
1891
+ header['content-type'] = 'multipart/mixed' unless header['content-type']
1892
+ header['content-type'].parameters[:boundary] = ContentTypeField.generate_boundary
1893
+ header['content_type'].parameters[:charset] = @charset
1894
+ body.boundary = boundary
1895
+ end
1896
+ end
1897
+
1898
+ def add_multipart_mixed_header
1899
+ unless header['content-type']
1900
+ header['content-type'] = ContentTypeField.with_boundary('multipart/mixed').value
1901
+ header['content_type'].parameters[:charset] = @charset
1902
+ body.boundary = boundary
1903
+ end
1904
+ end
1905
+
1906
+ def init_with_hash(hash)
1907
+ passed_in_options = hash.with_indifferent_access
1908
+ self.raw_source = ''
1909
+
1910
+ @header = Mail::Header.new
1911
+ @body = Mail::Body.new
1912
+ @body_raw = nil
1913
+
1914
+ # We need to store the body until last, as we need all headers added first
1915
+ body_content = nil
1916
+
1917
+ passed_in_options.each_pair do |k,v|
1918
+ k = underscoreize(k).to_sym if k.class == String
1919
+ if k == :headers
1920
+ self.headers(v)
1921
+ elsif k == :body
1922
+ body_content = v
1923
+ else
1924
+ self[k] = v
1925
+ end
1926
+ end
1927
+
1928
+ if body_content
1929
+ self.body = body_content
1930
+ if has_content_transfer_encoding?
1931
+ body.encoding = content_transfer_encoding
1932
+ end
1933
+ end
1934
+ end
1935
+
1936
+ def init_with_string(string)
1937
+ self.raw_source = string
1938
+ set_envelope_header
1939
+ parse_message
1940
+ @separate_parts = multipart?
1941
+ end
1942
+
1943
+ # Returns the filename of the attachment (if it exists) or returns nil
1944
+ def find_attachment
1945
+ content_type_name = header[:content_type].filename rescue nil
1946
+ content_disp_name = header[:content_disposition].filename rescue nil
1947
+ content_loc_name = header[:content_location].location rescue nil
1948
+ case
1949
+ when content_type && content_type_name
1950
+ filename = content_type_name
1951
+ when content_disposition && content_disp_name
1952
+ filename = content_disp_name
1953
+ when content_location && content_loc_name
1954
+ filename = content_loc_name
1955
+ else
1956
+ filename = nil
1957
+ end
1958
+ filename
1959
+ end
1960
+
1961
+ def do_delivery
1962
+ begin
1963
+ if perform_deliveries
1964
+ delivery_method.deliver!(self)
1965
+ end
1966
+ rescue Exception => e # Net::SMTP errors or sendmail pipe errors
1967
+ raise e if raise_delivery_errors
1968
+ end
1969
+ end
1970
+
1971
+ end
1972
+ end