dball-mail 2.2.9.1

Sign up to get free protection for your applications and to get access to all the features.
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