mail 2.5.5 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +5 -5
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +170 -108
  4. data/lib/mail/attachments_list.rb +13 -10
  5. data/lib/mail/body.rb +105 -91
  6. data/lib/mail/check_delivery_params.rb +30 -22
  7. data/lib/mail/configuration.rb +3 -0
  8. data/lib/mail/constants.rb +79 -0
  9. data/lib/mail/elements/address.rb +118 -174
  10. data/lib/mail/elements/address_list.rb +16 -56
  11. data/lib/mail/elements/content_disposition_element.rb +12 -22
  12. data/lib/mail/elements/content_location_element.rb +9 -17
  13. data/lib/mail/elements/content_transfer_encoding_element.rb +8 -19
  14. data/lib/mail/elements/content_type_element.rb +20 -30
  15. data/lib/mail/elements/date_time_element.rb +10 -21
  16. data/lib/mail/elements/envelope_from_element.rb +23 -31
  17. data/lib/mail/elements/message_ids_element.rb +22 -20
  18. data/lib/mail/elements/mime_version_element.rb +10 -21
  19. data/lib/mail/elements/phrase_list.rb +13 -15
  20. data/lib/mail/elements/received_element.rb +26 -21
  21. data/lib/mail/elements.rb +1 -0
  22. data/lib/mail/encodings/7bit.rb +10 -14
  23. data/lib/mail/encodings/8bit.rb +5 -18
  24. data/lib/mail/encodings/base64.rb +15 -10
  25. data/lib/mail/encodings/binary.rb +4 -22
  26. data/lib/mail/encodings/identity.rb +24 -0
  27. data/lib/mail/encodings/quoted_printable.rb +13 -7
  28. data/lib/mail/encodings/transfer_encoding.rb +47 -28
  29. data/lib/mail/encodings/unix_to_unix.rb +20 -0
  30. data/lib/mail/encodings.rb +102 -93
  31. data/lib/mail/envelope.rb +12 -19
  32. data/lib/mail/field.rb +143 -71
  33. data/lib/mail/field_list.rb +73 -19
  34. data/lib/mail/fields/bcc_field.rb +42 -48
  35. data/lib/mail/fields/cc_field.rb +29 -50
  36. data/lib/mail/fields/comments_field.rb +28 -37
  37. data/lib/mail/fields/common_address_field.rb +170 -0
  38. data/lib/mail/fields/common_date_field.rb +58 -0
  39. data/lib/mail/fields/common_field.rb +77 -0
  40. data/lib/mail/fields/common_message_id_field.rb +42 -0
  41. data/lib/mail/fields/content_description_field.rb +8 -14
  42. data/lib/mail/fields/content_disposition_field.rb +20 -44
  43. data/lib/mail/fields/content_id_field.rb +25 -51
  44. data/lib/mail/fields/content_location_field.rb +12 -25
  45. data/lib/mail/fields/content_transfer_encoding_field.rb +31 -36
  46. data/lib/mail/fields/content_type_field.rb +51 -80
  47. data/lib/mail/fields/date_field.rb +24 -52
  48. data/lib/mail/fields/from_field.rb +29 -50
  49. data/lib/mail/fields/in_reply_to_field.rb +39 -49
  50. data/lib/mail/fields/keywords_field.rb +19 -32
  51. data/lib/mail/fields/message_id_field.rb +26 -71
  52. data/lib/mail/fields/mime_version_field.rb +20 -30
  53. data/lib/mail/fields/named_structured_field.rb +11 -0
  54. data/lib/mail/fields/named_unstructured_field.rb +11 -0
  55. data/lib/mail/fields/optional_field.rb +10 -7
  56. data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +16 -13
  57. data/lib/mail/fields/received_field.rb +44 -57
  58. data/lib/mail/fields/references_field.rb +36 -49
  59. data/lib/mail/fields/reply_to_field.rb +29 -50
  60. data/lib/mail/fields/resent_bcc_field.rb +29 -50
  61. data/lib/mail/fields/resent_cc_field.rb +29 -50
  62. data/lib/mail/fields/resent_date_field.rb +6 -30
  63. data/lib/mail/fields/resent_from_field.rb +29 -50
  64. data/lib/mail/fields/resent_message_id_field.rb +6 -29
  65. data/lib/mail/fields/resent_sender_field.rb +28 -57
  66. data/lib/mail/fields/resent_to_field.rb +29 -50
  67. data/lib/mail/fields/return_path_field.rb +51 -55
  68. data/lib/mail/fields/sender_field.rb +35 -56
  69. data/lib/mail/fields/structured_field.rb +4 -30
  70. data/lib/mail/fields/subject_field.rb +10 -11
  71. data/lib/mail/fields/to_field.rb +29 -50
  72. data/lib/mail/fields/unstructured_field.rb +43 -51
  73. data/lib/mail/fields.rb +1 -0
  74. data/lib/mail/header.rb +78 -129
  75. data/lib/mail/indifferent_hash.rb +1 -0
  76. data/lib/mail/mail.rb +18 -11
  77. data/lib/mail/matchers/attachment_matchers.rb +44 -0
  78. data/lib/mail/matchers/has_sent_mail.rb +81 -4
  79. data/lib/mail/message.rb +142 -139
  80. data/lib/mail/multibyte/chars.rb +24 -180
  81. data/lib/mail/multibyte/unicode.rb +32 -27
  82. data/lib/mail/multibyte/utils.rb +27 -43
  83. data/lib/mail/multibyte.rb +56 -16
  84. data/lib/mail/network/delivery_methods/exim.rb +6 -4
  85. data/lib/mail/network/delivery_methods/file_delivery.rb +12 -10
  86. data/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
  87. data/lib/mail/network/delivery_methods/sendmail.rb +63 -21
  88. data/lib/mail/network/delivery_methods/smtp.rb +76 -50
  89. data/lib/mail/network/delivery_methods/smtp_connection.rb +4 -4
  90. data/lib/mail/network/delivery_methods/test_mailer.rb +5 -2
  91. data/lib/mail/network/retriever_methods/base.rb +9 -8
  92. data/lib/mail/network/retriever_methods/imap.rb +37 -18
  93. data/lib/mail/network/retriever_methods/pop3.rb +6 -3
  94. data/lib/mail/network/retriever_methods/test_retriever.rb +4 -2
  95. data/lib/mail/network.rb +2 -0
  96. data/lib/mail/parser_tools.rb +15 -0
  97. data/lib/mail/parsers/address_lists_parser.rb +33242 -0
  98. data/lib/mail/parsers/address_lists_parser.rl +179 -0
  99. data/lib/mail/parsers/content_disposition_parser.rb +901 -0
  100. data/lib/mail/parsers/content_disposition_parser.rl +89 -0
  101. data/lib/mail/parsers/content_location_parser.rb +822 -0
  102. data/lib/mail/parsers/content_location_parser.rl +78 -0
  103. data/lib/mail/parsers/content_transfer_encoding_parser.rb +522 -0
  104. data/lib/mail/parsers/content_transfer_encoding_parser.rl +71 -0
  105. data/lib/mail/parsers/content_type_parser.rb +1048 -0
  106. data/lib/mail/parsers/content_type_parser.rl +90 -0
  107. data/lib/mail/parsers/date_time_parser.rb +891 -0
  108. data/lib/mail/parsers/date_time_parser.rl +69 -0
  109. data/lib/mail/parsers/envelope_from_parser.rb +3675 -0
  110. data/lib/mail/parsers/envelope_from_parser.rl +89 -0
  111. data/lib/mail/parsers/message_ids_parser.rb +5161 -0
  112. data/lib/mail/parsers/message_ids_parser.rl +93 -0
  113. data/lib/mail/parsers/mime_version_parser.rb +513 -0
  114. data/lib/mail/parsers/mime_version_parser.rl +68 -0
  115. data/lib/mail/parsers/phrase_lists_parser.rb +884 -0
  116. data/lib/mail/parsers/phrase_lists_parser.rl +90 -0
  117. data/lib/mail/parsers/received_parser.rb +8782 -0
  118. data/lib/mail/parsers/received_parser.rl +91 -0
  119. data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
  120. data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
  121. data/lib/mail/parsers/rfc2045_mime.rl +16 -0
  122. data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
  123. data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  124. data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
  125. data/lib/mail/parsers/rfc5322.rl +74 -0
  126. data/lib/mail/parsers/rfc5322_address.rl +72 -0
  127. data/lib/mail/parsers/rfc5322_date_time.rl +37 -0
  128. data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
  129. data/lib/mail/parsers.rb +13 -0
  130. data/lib/mail/part.rb +11 -12
  131. data/lib/mail/parts_list.rb +90 -14
  132. data/lib/mail/smtp_envelope.rb +57 -0
  133. data/lib/mail/utilities.rb +415 -76
  134. data/lib/mail/values/unicode_tables.dat +0 -0
  135. data/lib/mail/version.rb +8 -15
  136. data/lib/mail/yaml.rb +30 -0
  137. data/lib/mail.rb +9 -32
  138. metadata +127 -79
  139. data/CHANGELOG.rdoc +0 -742
  140. data/CONTRIBUTING.md +0 -45
  141. data/Dependencies.txt +0 -3
  142. data/Gemfile +0 -32
  143. data/Rakefile +0 -21
  144. data/TODO.rdoc +0 -9
  145. data/lib/VERSION +0 -4
  146. data/lib/load_parsers.rb +0 -35
  147. data/lib/mail/core_extensions/nil.rb +0 -19
  148. data/lib/mail/core_extensions/object.rb +0 -13
  149. data/lib/mail/core_extensions/smtp.rb +0 -24
  150. data/lib/mail/core_extensions/string/access.rb +0 -145
  151. data/lib/mail/core_extensions/string/multibyte.rb +0 -78
  152. data/lib/mail/core_extensions/string.rb +0 -33
  153. data/lib/mail/fields/common/address_container.rb +0 -16
  154. data/lib/mail/fields/common/common_address.rb +0 -140
  155. data/lib/mail/fields/common/common_date.rb +0 -42
  156. data/lib/mail/fields/common/common_field.rb +0 -57
  157. data/lib/mail/fields/common/common_message_id.rb +0 -48
  158. data/lib/mail/multibyte/exceptions.rb +0 -8
  159. data/lib/mail/parsers/address_lists.rb +0 -64
  160. data/lib/mail/parsers/address_lists.treetop +0 -19
  161. data/lib/mail/parsers/content_disposition.rb +0 -535
  162. data/lib/mail/parsers/content_disposition.treetop +0 -46
  163. data/lib/mail/parsers/content_location.rb +0 -139
  164. data/lib/mail/parsers/content_location.treetop +0 -20
  165. data/lib/mail/parsers/content_transfer_encoding.rb +0 -201
  166. data/lib/mail/parsers/content_transfer_encoding.treetop +0 -18
  167. data/lib/mail/parsers/content_type.rb +0 -971
  168. data/lib/mail/parsers/content_type.treetop +0 -68
  169. data/lib/mail/parsers/date_time.rb +0 -114
  170. data/lib/mail/parsers/date_time.treetop +0 -11
  171. data/lib/mail/parsers/envelope_from.rb +0 -194
  172. data/lib/mail/parsers/envelope_from.treetop +0 -32
  173. data/lib/mail/parsers/message_ids.rb +0 -45
  174. data/lib/mail/parsers/message_ids.treetop +0 -15
  175. data/lib/mail/parsers/mime_version.rb +0 -144
  176. data/lib/mail/parsers/mime_version.treetop +0 -19
  177. data/lib/mail/parsers/phrase_lists.rb +0 -45
  178. data/lib/mail/parsers/phrase_lists.treetop +0 -15
  179. data/lib/mail/parsers/received.rb +0 -71
  180. data/lib/mail/parsers/received.treetop +0 -11
  181. data/lib/mail/parsers/rfc2045.rb +0 -421
  182. data/lib/mail/parsers/rfc2045.treetop +0 -35
  183. data/lib/mail/parsers/rfc2822.rb +0 -5397
  184. data/lib/mail/parsers/rfc2822.treetop +0 -408
  185. data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
  186. data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
  187. data/lib/mail/patterns.rb +0 -35
  188. data/lib/mail/version_specific/ruby_1_8.rb +0 -119
  189. data/lib/mail/version_specific/ruby_1_9.rb +0 -147
  190. data/lib/tasks/corpus.rake +0 -125
  191. data/lib/tasks/treetop.rake +0 -10
@@ -1,35 +1,25 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/content_type_parser'
4
+
2
5
  module Mail
3
- class ContentTypeElement # :nodoc:
4
-
5
- include Mail::Utilities
6
-
7
- def initialize( string )
8
- parser = Mail::ContentTypeParser.new
9
- if tree = parser.parse(cleaned(string))
10
- @main_type = tree.main_type.text_value.downcase
11
- @sub_type = tree.sub_type.text_value.downcase
12
- @parameters = tree.parameters
13
- else
14
- raise Mail::Field::ParseError.new(ContentTypeElement, string, parser.failure_reason)
15
- end
16
- end
17
-
18
- def main_type
19
- @main_type
20
- end
21
-
22
- def sub_type
23
- @sub_type
6
+ class ContentTypeElement #:nodoc:
7
+ attr_reader :main_type, :sub_type, :parameters
8
+
9
+ def initialize(string)
10
+ content_type = Mail::Parsers::ContentTypeParser.parse(cleaned(string))
11
+ @main_type = content_type.main_type
12
+ @sub_type = content_type.sub_type
13
+ @parameters = content_type.parameters
24
14
  end
25
-
26
- def parameters
27
- @parameters
28
- end
29
-
30
- def cleaned(string)
31
- string =~ /(.+);\s*$/ ? $1 : string
32
- end
33
-
15
+
16
+ private
17
+ def cleaned(string)
18
+ if string =~ /;\s*$/
19
+ $`
20
+ else
21
+ string
22
+ end
23
+ end
34
24
  end
35
25
  end
@@ -1,26 +1,15 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/date_time_parser'
4
+
2
5
  module Mail
3
- class DateTimeElement # :nodoc:
4
-
5
- include Mail::Utilities
6
-
7
- def initialize( string )
8
- parser = Mail::DateTimeParser.new
9
- if tree = parser.parse(string)
10
- @date_string = tree.date.text_value
11
- @time_string = tree.time.text_value
12
- else
13
- raise Mail::Field::ParseError.new(DateTimeElement, string, parser.failure_reason)
14
- end
6
+ class DateTimeElement #:nodoc:
7
+ attr_reader :date_string, :time_string
8
+
9
+ def initialize(string)
10
+ date_time = Mail::Parsers::DateTimeParser.parse(string)
11
+ @date_string = date_time.date_string
12
+ @time_string = date_time.time_string
15
13
  end
16
-
17
- def date_string
18
- @date_string
19
- end
20
-
21
- def time_string
22
- @time_string
23
- end
24
-
25
14
  end
26
15
  end
@@ -1,47 +1,39 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/envelope_from_parser'
4
+ require 'date'
5
+
2
6
  module Mail
3
- class EnvelopeFromElement
4
-
5
- include Mail::Utilities
6
-
7
- def initialize( string )
8
- parser = Mail::EnvelopeFromParser.new
9
- if @tree = parser.parse(string)
10
- @address = tree.addr_spec.text_value.strip
11
- @date_time = ::DateTime.parse("#{tree.ctime_date.text_value}")
12
- else
13
- raise Mail::Field::ParseError.new(EnvelopeFromElement, string, parser.failure_reason)
14
- end
15
- end
16
-
17
- def tree
18
- @tree
19
- end
20
-
21
- def date_time
22
- @date_time
23
- end
24
-
25
- def address
26
- @address
7
+ class EnvelopeFromElement #:nodoc:
8
+ attr_reader :date_time, :address
9
+
10
+ def initialize(string)
11
+ envelope_from = Mail::Parsers::EnvelopeFromParser.parse(string)
12
+ @address = envelope_from.address
13
+ @date_time = ::DateTime.parse(envelope_from.ctime_date) if envelope_from.ctime_date
27
14
  end
28
-
15
+
29
16
  # RFC 4155:
30
17
  # a timestamp indicating the UTC date and time when the message
31
18
  # was originally received, conformant with the syntax of the
32
19
  # traditional UNIX 'ctime' output sans timezone (note that the
33
20
  # use of UTC precludes the need for a timezone indicator);
34
21
  def formatted_date_time
35
- if @date_time.respond_to?(:ctime)
36
- @date_time.ctime
37
- else
38
- @date_time.strftime '%a %b %e %T %Y'
22
+ if date_time
23
+ if date_time.respond_to?(:ctime)
24
+ date_time.ctime
25
+ else
26
+ date_time.strftime '%a %b %e %T %Y'
27
+ end
39
28
  end
40
29
  end
41
30
 
42
31
  def to_s
43
- "#{@address} #{formatted_date_time}"
32
+ if date_time
33
+ "#{address} #{formatted_date_time}"
34
+ else
35
+ address
36
+ end
44
37
  end
45
-
46
38
  end
47
39
  end
@@ -1,29 +1,31 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/message_ids_parser'
4
+ require 'mail/utilities'
5
+
2
6
  module Mail
3
- class MessageIdsElement
4
-
5
- include Mail::Utilities
6
-
7
- def initialize(string)
8
- parser = Mail::MessageIdsParser.new
9
- if tree = parser.parse(string)
10
- @message_ids = tree.message_ids.map { |msg_id| clean_msg_id(msg_id.text_value) }
11
- else
12
- raise Mail::Field::ParseError.new(MessageIdsElement, string, parser.failure_reason)
13
- end
7
+ class MessageIdsElement #:nodoc:
8
+ def self.parse(string)
9
+ new(string).tap(&:message_ids)
14
10
  end
15
-
16
- def message_ids
17
- @message_ids
11
+
12
+ attr_reader :message_ids
13
+
14
+ def initialize(string)
15
+ @message_ids = parse(string)
18
16
  end
19
-
17
+
20
18
  def message_id
21
- @message_ids.first
22
- end
23
-
24
- def clean_msg_id( val )
25
- val =~ /.*<(.*)>.*/ ; $1
19
+ message_ids.first
26
20
  end
27
21
 
22
+ private
23
+ def parse(string)
24
+ if Utilities.blank? string
25
+ []
26
+ else
27
+ Mail::Parsers::MessageIdsParser.parse(string).message_ids
28
+ end
29
+ end
28
30
  end
29
31
  end
@@ -1,26 +1,15 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/mime_version_parser'
4
+
2
5
  module Mail
3
- class MimeVersionElement
4
-
5
- include Mail::Utilities
6
-
7
- def initialize( string )
8
- parser = Mail::MimeVersionParser.new
9
- if tree = parser.parse(string)
10
- @major = tree.major.text_value
11
- @minor = tree.minor.text_value
12
- else
13
- raise Mail::Field::ParseError.new(MimeVersionElement, string, parser.failure_reason)
14
- end
6
+ class MimeVersionElement #:nodoc:
7
+ attr_reader :major, :minor
8
+
9
+ def initialize(string)
10
+ mime_version = Mail::Parsers::MimeVersionParser.parse(string)
11
+ @major = mime_version.major
12
+ @minor = mime_version.minor
15
13
  end
16
-
17
- def major
18
- @major
19
- end
20
-
21
- def minor
22
- @minor
23
- end
24
-
25
14
  end
26
15
  end
@@ -1,21 +1,19 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/phrase_lists_parser'
4
+ require 'mail/utilities'
5
+
2
6
  module Mail
3
- class PhraseList
4
-
5
- include Mail::Utilities
6
-
7
+ class PhraseList #:nodoc:
8
+ attr_reader :phrases
9
+
7
10
  def initialize(string)
8
- parser = Mail::PhraseListsParser.new
9
- if tree = parser.parse(string)
10
- @phrases = tree.phrases
11
- else
12
- raise Mail::Field::ParseError.new(PhraseList, string, parser.failure_reason)
13
- end
11
+ @phrases =
12
+ if Utilities.blank? string
13
+ []
14
+ else
15
+ Mail::Parsers::PhraseListsParser.parse(string).phrases.map { |p| Mail::Utilities.unquote(p) }
16
+ end
14
17
  end
15
-
16
- def phrases
17
- @phrases.map { |p| unquote(p.text_value) }
18
- end
19
-
20
18
  end
21
19
  end
@@ -1,30 +1,35 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/parsers/received_parser'
4
+ require 'mail/utilities'
5
+ require 'date'
6
+
2
7
  module Mail
3
- class ReceivedElement
4
-
5
- include Mail::Utilities
6
-
7
- def initialize( string )
8
- parser = Mail::ReceivedParser.new
9
- if tree = parser.parse(string)
10
- @date_time = ::DateTime.parse("#{tree.date_time.date.text_value} #{tree.date_time.time.text_value}")
11
- @info = tree.name_val_list.text_value
8
+ class ReceivedElement #:nodoc:
9
+ attr_reader :info, :date_time
10
+
11
+ def initialize(string)
12
+ if Utilities.blank? string
13
+ @date_time = nil
14
+ @info = nil
12
15
  else
13
- raise Mail::Field::ParseError.new(ReceivedElement, string, parser.failure_reason)
16
+ received = Mail::Parsers::ReceivedParser.parse(string)
17
+ @date_time = datetime_for(received)
18
+ @info = received.info
14
19
  end
15
20
  end
16
-
17
- def date_time
18
- @date_time
19
- end
20
-
21
- def info
22
- @info
23
- end
24
-
21
+
25
22
  def to_s(*args)
26
- "#{@info}; #{@date_time.to_s(*args)}"
23
+ "#{info}; #{date_time.to_s(*args)}"
27
24
  end
28
-
25
+
26
+ private
27
+ def datetime_for(received)
28
+ ::DateTime.parse("#{received.date} #{received.time}")
29
+ rescue ArgumentError => e
30
+ raise e unless e.message == 'invalid date'
31
+ warn "WARNING: Invalid date field for received element (#{received.date} #{received.time}): #{e.class}: #{e.message}"
32
+ nil
33
+ end
29
34
  end
30
35
  end
data/lib/mail/elements.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Mail
2
3
  register_autoload :Address, 'mail/elements/address'
3
4
  register_autoload :AddressList, 'mail/elements/address_list'
@@ -1,31 +1,27 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
  require 'mail/encodings/8bit'
3
4
 
4
5
  module Mail
5
6
  module Encodings
7
+ # 7bit and 8bit are equivalent. 7bit encoding is for text only.
6
8
  class SevenBit < EightBit
7
9
  NAME = '7bit'
8
-
9
10
  PRIORITY = 1
11
+ Encodings.register(NAME, self)
10
12
 
11
- # 7bit and 8bit operate the same
12
-
13
- # Decode the string
14
13
  def self.decode(str)
15
- super
14
+ ::Mail::Utilities.binary_unsafe_to_lf str
16
15
  end
17
-
18
- # Encode the string
16
+
19
17
  def self.encode(str)
20
- super
21
- end
22
-
23
- # Idenity encodings have a fixed cost, 1 byte out per 1 byte in
24
- def self.cost(str)
25
- super
18
+ ::Mail::Utilities.binary_unsafe_to_crlf str
26
19
  end
27
20
 
28
- Encodings.register(NAME, self)
21
+ # Per RFC 2045 2.7. 7bit Data, No octets with decimal values greater than 127 are allowed.
22
+ def self.compatible_input?(str)
23
+ str.ascii_only? && super
24
+ end
29
25
  end
30
26
  end
31
27
  end
@@ -1,31 +1,18 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
  require 'mail/encodings/binary'
3
4
 
4
5
  module Mail
5
6
  module Encodings
6
7
  class EightBit < Binary
7
8
  NAME = '8bit'
8
-
9
9
  PRIORITY = 4
10
+ Encodings.register(NAME, self)
10
11
 
11
- # 8bit is an identiy encoding, meaning nothing to do
12
-
13
- # Decode the string
14
- def self.decode(str)
15
- str.to_lf
16
- end
17
-
18
- # Encode the string
19
- def self.encode(str)
20
- str.to_crlf
12
+ # Per RFC 2821 4.5.3.1, SMTP lines may not be longer than 1000 octets including the <CRLF>.
13
+ def self.compatible_input?(str)
14
+ !str.lines.find { |line| line.bytesize > 998 }
21
15
  end
22
-
23
- # Idenity encodings have a fixed cost, 1 byte out per 1 byte in
24
- def self.cost(str)
25
- 1.0
26
- end
27
-
28
- Encodings.register(NAME, self)
29
16
  end
30
17
  end
31
18
  end
@@ -1,33 +1,38 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
  require 'mail/encodings/7bit'
3
4
 
4
5
  module Mail
5
6
  module Encodings
7
+ # Base64 encoding handles binary content at the cost of 4 output bytes
8
+ # per input byte.
6
9
  class Base64 < SevenBit
7
10
  NAME = 'base64'
8
-
9
11
  PRIORITY = 3
10
-
12
+ Encodings.register(NAME, self)
13
+
11
14
  def self.can_encode?(enc)
12
15
  true
13
16
  end
14
17
 
15
- # Decode the string from Base64
16
18
  def self.decode(str)
17
- RubyVer.decode_base64( str )
19
+ Utilities.decode_base64(str)
18
20
  end
19
-
20
- # Encode the string to Base64
21
+
21
22
  def self.encode(str)
22
- RubyVer.encode_base64( str ).to_crlf
23
+ ::Mail::Utilities.binary_unsafe_to_crlf(Utilities.encode_base64(str))
23
24
  end
24
25
 
25
- # Base64 has a fixed cost, 4 bytes out per 3 bytes in
26
+ # 3 bytes in -> 4 bytes out
26
27
  def self.cost(str)
27
- 4.0/3
28
+ 4.0 / 3
28
29
  end
29
30
 
30
- Encodings.register(NAME, self)
31
+ # Ruby Base64 inserts newlines automatically, so it doesn't exceed
32
+ # SMTP line length limits.
33
+ def self.compatible_input?(str)
34
+ true
35
+ end
31
36
  end
32
37
  end
33
38
  end
@@ -1,31 +1,13 @@
1
1
  # encoding: utf-8
2
- require 'mail/encodings/transfer_encoding'
2
+ # frozen_string_literal: true
3
+ require 'mail/encodings/identity'
3
4
 
4
5
  module Mail
5
6
  module Encodings
6
- class Binary < TransferEncoding
7
+ class Binary < Identity
7
8
  NAME = 'binary'
8
-
9
9
  PRIORITY = 5
10
-
11
- # Binary is an identiy encoding, meaning nothing to do
12
-
13
- # Decode the string
14
- def self.decode(str)
15
- str
16
- end
17
-
18
- # Encode the string
19
- def self.encode(str)
20
- str
21
- end
22
-
23
- # Idenity encodings have a fixed cost, 1 byte out per 1 byte in
24
- def self.cost(str)
25
- 1.0
26
- end
27
-
28
- Encodings.register(NAME, self)
10
+ Encodings.register(NAME, self)
29
11
  end
30
12
  end
31
13
  end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/encodings/transfer_encoding'
4
+
5
+ module Mail
6
+ module Encodings
7
+ # Identity encodings do no encoding/decoding and have a fixed cost:
8
+ # 1 byte in -> 1 byte out.
9
+ class Identity < TransferEncoding #:nodoc:
10
+ def self.decode(str)
11
+ str
12
+ end
13
+
14
+ def self.encode(str)
15
+ str
16
+ end
17
+
18
+ # 1 output byte per input byte.
19
+ def self.cost(str)
20
+ 1.0
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,36 +1,42 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
  require 'mail/encodings/7bit'
3
4
 
4
5
  module Mail
5
6
  module Encodings
6
7
  class QuotedPrintable < SevenBit
7
8
  NAME='quoted-printable'
8
-
9
+
9
10
  PRIORITY = 2
10
11
 
11
- def self.can_encode?(str)
12
- EightBit.can_encode? str
12
+ def self.can_encode?(enc)
13
+ EightBit.can_encode? enc
13
14
  end
14
15
 
15
16
  # Decode the string from Quoted-Printable. Cope with hard line breaks
16
17
  # that were incorrectly encoded as hex instead of literal CRLF.
17
18
  def self.decode(str)
18
- str.gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first.to_lf
19
+ ::Mail::Utilities.to_lf ::Mail::Utilities.to_crlf(str).gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first
19
20
  end
20
21
 
21
22
  def self.encode(str)
22
- [str.to_lf].pack("M").to_crlf
23
+ ::Mail::Utilities.to_crlf [::Mail::Utilities.to_lf(str)].pack("M")
23
24
  end
24
25
 
25
26
  def self.cost(str)
26
27
  # These bytes probably do not need encoding
27
28
  c = str.count("\x9\xA\xD\x20-\x3C\x3E-\x7E")
28
- # Everything else turns into =XX where XX is a
29
+ # Everything else turns into =XX where XX is a
29
30
  # two digit hex number (taking 3 bytes)
30
31
  total = (str.bytesize - c)*3 + c
31
32
  total.to_f/str.bytesize
32
33
  end
33
-
34
+
35
+ # QP inserts newlines automatically and cannot violate the SMTP spec.
36
+ def self.compatible_input?(str)
37
+ true
38
+ end
39
+
34
40
  private
35
41
 
36
42
  Encodings.register(NAME, self)