message.rb 64 KB

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