PageRenderTime 44ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/External.LCA_RESTRICTED/Languages/Ruby/ruby19/lib/ruby/gems/1.9.1/gems/mail-2.2.5/lib/mail/message.rb

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