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