mail 2.7.0.rc1 → 2.7.0.rc2

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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +71 -98
  3. data/lib/mail.rb +1 -6
  4. data/lib/mail/attachments_list.rb +5 -2
  5. data/lib/mail/body.rb +39 -33
  6. data/lib/mail/check_delivery_params.rb +8 -6
  7. data/lib/mail/configuration.rb +2 -0
  8. data/lib/mail/elements/address.rb +19 -18
  9. data/lib/mail/encodings.rb +89 -31
  10. data/lib/mail/encodings/7bit.rb +5 -15
  11. data/lib/mail/encodings/8bit.rb +2 -21
  12. data/lib/mail/encodings/base64.rb +11 -12
  13. data/lib/mail/encodings/binary.rb +3 -22
  14. data/lib/mail/encodings/identity.rb +24 -0
  15. data/lib/mail/encodings/quoted_printable.rb +6 -6
  16. data/lib/mail/encodings/transfer_encoding.rb +38 -29
  17. data/lib/mail/encodings/unix_to_unix.rb +2 -1
  18. data/lib/mail/envelope.rb +1 -1
  19. data/lib/mail/field.rb +93 -61
  20. data/lib/mail/fields/bcc_field.rb +2 -2
  21. data/lib/mail/fields/cc_field.rb +1 -1
  22. data/lib/mail/fields/comments_field.rb +1 -1
  23. data/lib/mail/fields/common/common_address.rb +32 -7
  24. data/lib/mail/fields/common/common_field.rb +1 -10
  25. data/lib/mail/fields/content_description_field.rb +1 -1
  26. data/lib/mail/fields/content_disposition_field.rb +3 -3
  27. data/lib/mail/fields/content_id_field.rb +2 -2
  28. data/lib/mail/fields/content_location_field.rb +1 -1
  29. data/lib/mail/fields/content_transfer_encoding_field.rb +1 -1
  30. data/lib/mail/fields/content_type_field.rb +1 -1
  31. data/lib/mail/fields/date_field.rb +2 -3
  32. data/lib/mail/fields/from_field.rb +1 -1
  33. data/lib/mail/fields/in_reply_to_field.rb +1 -1
  34. data/lib/mail/fields/keywords_field.rb +1 -1
  35. data/lib/mail/fields/message_id_field.rb +1 -1
  36. data/lib/mail/fields/mime_version_field.rb +1 -1
  37. data/lib/mail/fields/optional_field.rb +4 -1
  38. data/lib/mail/fields/received_field.rb +1 -1
  39. data/lib/mail/fields/references_field.rb +1 -1
  40. data/lib/mail/fields/reply_to_field.rb +1 -1
  41. data/lib/mail/fields/resent_bcc_field.rb +1 -1
  42. data/lib/mail/fields/resent_cc_field.rb +1 -1
  43. data/lib/mail/fields/resent_date_field.rb +0 -1
  44. data/lib/mail/fields/resent_from_field.rb +1 -1
  45. data/lib/mail/fields/resent_message_id_field.rb +1 -1
  46. data/lib/mail/fields/resent_sender_field.rb +1 -1
  47. data/lib/mail/fields/resent_to_field.rb +1 -1
  48. data/lib/mail/fields/return_path_field.rb +1 -1
  49. data/lib/mail/fields/sender_field.rb +1 -1
  50. data/lib/mail/fields/subject_field.rb +1 -1
  51. data/lib/mail/fields/to_field.rb +1 -1
  52. data/lib/mail/fields/unstructured_field.rb +19 -2
  53. data/lib/mail/header.rb +9 -8
  54. data/lib/mail/mail.rb +2 -10
  55. data/lib/mail/matchers/has_sent_mail.rb +21 -1
  56. data/lib/mail/message.rb +64 -51
  57. data/lib/mail/multibyte.rb +14 -16
  58. data/lib/mail/multibyte/chars.rb +2 -1
  59. data/lib/mail/network.rb +1 -0
  60. data/lib/mail/network/delivery_methods/exim.rb +6 -10
  61. data/lib/mail/network/delivery_methods/logger_delivery.rb +37 -0
  62. data/lib/mail/network/delivery_methods/sendmail.rb +8 -4
  63. data/lib/mail/network/delivery_methods/smtp.rb +56 -55
  64. data/lib/mail/network/delivery_methods/smtp_connection.rb +9 -1
  65. data/lib/mail/network/retriever_methods/imap.rb +18 -5
  66. data/lib/mail/network/retriever_methods/pop3.rb +3 -1
  67. data/lib/mail/parser_tools.rb +15 -0
  68. data/lib/mail/parsers/address_lists_parser.rb +30462 -12597
  69. data/lib/mail/parsers/address_lists_parser.rl +18 -12
  70. data/lib/mail/parsers/content_disposition_parser.rb +405 -215
  71. data/lib/mail/parsers/content_disposition_parser.rl +11 -5
  72. data/lib/mail/parsers/content_location_parser.rb +443 -208
  73. data/lib/mail/parsers/content_location_parser.rl +9 -3
  74. data/lib/mail/parsers/content_transfer_encoding_parser.rb +180 -80
  75. data/lib/mail/parsers/content_transfer_encoding_parser.rl +8 -2
  76. data/lib/mail/parsers/content_type_parser.rb +436 -245
  77. data/lib/mail/parsers/content_type_parser.rl +12 -6
  78. data/lib/mail/parsers/date_time_parser.rb +172 -72
  79. data/lib/mail/parsers/date_time_parser.rl +10 -4
  80. data/lib/mail/parsers/envelope_from_parser.rb +2833 -1320
  81. data/lib/mail/parsers/envelope_from_parser.rl +9 -3
  82. data/lib/mail/parsers/message_ids_parser.rb +2325 -976
  83. data/lib/mail/parsers/message_ids_parser.rl +9 -3
  84. data/lib/mail/parsers/mime_version_parser.rb +164 -64
  85. data/lib/mail/parsers/mime_version_parser.rl +9 -3
  86. data/lib/mail/parsers/phrase_lists_parser.rb +582 -237
  87. data/lib/mail/parsers/phrase_lists_parser.rl +9 -3
  88. data/lib/mail/parsers/received_parser.rb +7036 -3004
  89. data/lib/mail/parsers/received_parser.rl +11 -5
  90. data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +1 -0
  91. data/lib/mail/parsers/rfc2045_content_type.rl +1 -0
  92. data/lib/mail/parsers/rfc2045_mime.rl +1 -0
  93. data/lib/mail/parsers/rfc2183_content_disposition.rl +1 -0
  94. data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  95. data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +7 -1
  96. data/lib/mail/parsers/rfc5322.rl +3 -1
  97. data/lib/mail/parsers/rfc5322_address.rl +3 -1
  98. data/lib/mail/parsers/rfc5322_date_time.rl +1 -0
  99. data/lib/mail/parsers/rfc5322_lexical_tokens.rl +9 -5
  100. data/lib/mail/part.rb +1 -1
  101. data/lib/mail/utilities.rb +44 -15
  102. data/lib/mail/version.rb +1 -1
  103. data/lib/mail/version_specific/ruby_1_8.rb +12 -1
  104. data/lib/mail/version_specific/ruby_1_9.rb +13 -1
  105. metadata +7 -13
  106. data/CHANGELOG.rdoc +0 -822
  107. data/CONTRIBUTING.md +0 -60
  108. data/Dependencies.txt +0 -1
  109. data/Gemfile +0 -11
  110. data/Rakefile +0 -23
  111. data/TODO.rdoc +0 -9
  112. data/lib/mail/multibyte/exceptions.rb +0 -9
@@ -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
@@ -6,27 +6,27 @@ module Mail
6
6
  module Encodings
7
7
  class QuotedPrintable < SevenBit
8
8
  NAME='quoted-printable'
9
-
9
+
10
10
  PRIORITY = 2
11
11
 
12
- def self.can_encode?(str)
13
- EightBit.can_encode? str
12
+ def self.can_encode?(enc)
13
+ EightBit.can_encode? enc
14
14
  end
15
15
 
16
16
  # Decode the string from Quoted-Printable. Cope with hard line breaks
17
17
  # that were incorrectly encoded as hex instead of literal CRLF.
18
18
  def self.decode(str)
19
- ::Mail::Utilities.to_lf str.gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first
19
+ str.gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first
20
20
  end
21
21
 
22
22
  def self.encode(str)
23
- ::Mail::Utilities.to_crlf([::Mail::Utilities.to_lf(str)].pack("M"))
23
+ [str].pack("M")
24
24
  end
25
25
 
26
26
  def self.cost(str)
27
27
  # These bytes probably do not need encoding
28
28
  c = str.count("\x9\xA\xD\x20-\x3C\x3E-\x7E")
29
- # Everything else turns into =XX where XX is a
29
+ # Everything else turns into =XX where XX is a
30
30
  # two digit hex number (taking 3 bytes)
31
31
  total = (str.bytesize - c)*3 + c
32
32
  total.to_f/str.bytesize
@@ -7,17 +7,17 @@ module Mail
7
7
 
8
8
  PRIORITY = -1
9
9
 
10
+ # And encoding's superclass can always transport it since the
11
+ # class hierarchy is arranged e.g. Base64 < 7bit < 8bit < Binary.
10
12
  def self.can_transport?(enc)
11
- enc = Encodings.get_name(enc)
12
- if Encodings.defined? enc
13
- Encodings.get_encoding(enc).new.is_a? self
14
- else
15
- false
16
- end
13
+ enc && enc <= self
17
14
  end
18
15
 
16
+ # Override in subclasses to indicate that they can encode text
17
+ # that couldn't be directly transported, e.g. Base64 has 7bit output,
18
+ # but it can encode binary.
19
19
  def self.can_encode?(enc)
20
- can_transport? enc
20
+ can_transport? enc
21
21
  end
22
22
 
23
23
  def self.cost(str)
@@ -32,36 +32,45 @@ module Mail
32
32
  self::NAME
33
33
  end
34
34
 
35
- def self.get_best_compatible(source_encoding, str)
36
- if self.can_transport?(source_encoding) && self.compatible_input?(str)
35
+ def self.negotiate(message_encoding, source_encoding, str, allowed_encodings = nil)
36
+ message_encoding = Encodings.get_encoding(message_encoding || '8bit')
37
+ source_encoding = Encodings.get_encoding(source_encoding)
38
+
39
+ if message_encoding && source_encoding && message_encoding.can_transport?(source_encoding) && source_encoding.compatible_input?(str)
37
40
  source_encoding
38
41
  else
39
- choices = Encodings.get_all.select do |enc|
40
- self.can_transport?(enc) && enc.can_encode?(source_encoding)
41
- end
42
+ renegotiate(message_encoding, source_encoding, str, allowed_encodings)
43
+ end
44
+ end
42
45
 
43
- best = nil
44
- best_cost = nil
46
+ def self.renegotiate(message_encoding, source_encoding, str, allowed_encodings = nil)
47
+ encodings = Encodings.get_all.select do |enc|
48
+ (allowed_encodings.nil? || allowed_encodings.include?(enc)) &&
49
+ message_encoding.can_transport?(enc) &&
50
+ enc.can_encode?(source_encoding)
51
+ end
45
52
 
46
- choices.each do |enc|
47
- # If the current choice cannot be transported safely,
48
- # give priority to other choices but allow it to be used as a fallback.
49
- this_cost = enc.cost(str) if enc.compatible_input?(str)
53
+ lowest_cost(str, encodings)
54
+ end
50
55
 
51
- if !best_cost || (this_cost && this_cost < best_cost)
52
- best_cost = this_cost
53
- best = enc
54
- elsif this_cost == best_cost
55
- best = enc if enc::PRIORITY < best::PRIORITY
56
- end
57
- end
56
+ def self.lowest_cost(str, encodings)
57
+ best = nil
58
+ best_cost = nil
58
59
 
59
- best
60
+ encodings.each do |enc|
61
+ # If the current choice cannot be transported safely, give priority
62
+ # to other choices but allow it to be used as a fallback.
63
+ this_cost = enc.cost(str) if enc.compatible_input?(str)
64
+
65
+ if !best_cost || (this_cost && this_cost < best_cost)
66
+ best_cost = this_cost
67
+ best = enc
68
+ elsif this_cost == best_cost
69
+ best = enc if enc::PRIORITY < best::PRIORITY
70
+ end
60
71
  end
61
- end
62
72
 
63
- def to_s
64
- self.class.to_s
73
+ best
65
74
  end
66
75
  end
67
76
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module Mail
3
3
  module Encodings
4
- module UnixToUnix
4
+ class UnixToUnix < TransferEncoding
5
5
  NAME = "x-uuencode"
6
6
 
7
7
  def self.decode(str)
@@ -13,6 +13,7 @@ module Mail
13
13
  end
14
14
 
15
15
  Encodings.register(NAME, self)
16
+ Encodings.register("uuencode", self)
16
17
  end
17
18
  end
18
19
  end
@@ -12,7 +12,7 @@ module Mail
12
12
  class Envelope < StructuredField
13
13
 
14
14
  def initialize(*args)
15
- super(FIELD_NAME, strip_field(FIELD_NAME, args.last))
15
+ super(FIELD_NAME, args.last.to_s)
16
16
  end
17
17
 
18
18
  def element
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require 'mail/fields'
3
+ require 'mail/constants'
3
4
 
4
5
  # encoding: utf-8
5
6
  module Mail
@@ -83,9 +84,31 @@ module Mail
83
84
 
84
85
  def initialize(element, value, reason)
85
86
  @element = element
86
- @value = value
87
- @reason = reason
88
- super("#{element} can not parse |#{value}|\nReason was: #{reason}")
87
+ @value = to_utf8(value)
88
+ @reason = to_utf8(reason)
89
+ super("#{@element} can not parse |#{@value}|: #{@reason}")
90
+ end
91
+
92
+ private
93
+ def to_utf8(text)
94
+ if text.respond_to?(:force_encoding)
95
+ text.dup.force_encoding(Encoding::UTF_8)
96
+ else
97
+ text
98
+ end
99
+ end
100
+ end
101
+
102
+ class NilParseError < ParseError #:nodoc:
103
+ def initialize(element)
104
+ super element, nil, 'nil is invalid'
105
+ end
106
+ end
107
+
108
+ class IncompleteParseError < ParseError #:nodoc:
109
+ def initialize(element, original_text, unparsed_index)
110
+ parsed_text = to_utf8(original_text[0...unparsed_index])
111
+ super element, original_text, "Only able to parse up to #{parsed_text.inspect}"
89
112
  end
90
113
  end
91
114
 
@@ -93,41 +116,62 @@ module Mail
93
116
  class SyntaxError < FieldError #:nodoc:
94
117
  end
95
118
 
96
- # Accepts a string:
97
- #
98
- # Field.new("field-name: field data")
99
- #
100
- # Or name, value pair:
101
- #
102
- # Field.new("field-name", "value")
119
+ class << self
120
+ # Parse a field from a raw header line:
121
+ #
122
+ # Mail::Field.parse("field-name: field data")
123
+ # # => #<Mail::Field …>
124
+ def parse(field, charset = nil)
125
+ name, value = split(field)
126
+ if name && value
127
+ new name, value, charset
128
+ end
129
+ end
130
+
131
+ def split(raw_field) #:nodoc:
132
+ if raw_field.index(Constants::COLON)
133
+ name, value = raw_field.split(Constants::COLON, 2)
134
+ name.rstrip!
135
+ if name =~ /\A#{Constants::FIELD_NAME}\z/
136
+ [ name.rstrip, value.strip ]
137
+ else
138
+ Kernel.warn "WARNING: Ignoring unparsable header #{raw_field.inspect}: invalid header name syntax: #{name.inspect}"
139
+ nil
140
+ end
141
+ else
142
+ raw_field.strip
143
+ end
144
+ rescue => error
145
+ warn "WARNING: Ignoring unparsable header #{raw_field.inspect}: #{error.class}: #{error.message}"
146
+ nil
147
+ end
148
+ end
149
+
150
+ # Create a field by name and optional value:
103
151
  #
104
- # Or a name by itself:
152
+ # Mail::Field.new("field-name", "value")
153
+ # # => #<Mail::Field …>
105
154
  #
106
- # Field.new("field-name")
155
+ # Values that aren't strings or arrays are coerced to Strings with `#to_s`.
107
156
  #
108
- # Note, does not want a terminating carriage return. Returns
109
- # self appropriately parsed. If value is not a string, then
110
- # it will be passed through as is, for example, content-type
111
- # field can accept an array with the type and a hash of
112
- # parameters:
157
+ # Mail::Field.new("field-name", 1234)
158
+ # # => #<Mail::Field …>
113
159
  #
114
- # Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}])
160
+ # Mail::Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}])
161
+ # # => #<Mail::Field …>
115
162
  def initialize(name, value = nil, charset = 'utf-8')
116
163
  case
117
- when name.index(COLON) # Field.new("field-name: field data")
164
+ when name.index(COLON)
165
+ Kernel.warn 'Passing an unparsed header field to Mail::Field.new is deprecated and will be removed in Mail 2.8.0. Use Mail::Field.parse instead.'
166
+ @name, @unparsed_value = self.class.split(name)
118
167
  @charset = Utilities.blank?(value) ? charset : value
119
- @name = name[FIELD_PREFIX]
120
- @raw_value = name
121
- @value = nil
122
- when Utilities.blank?(value) # Field.new("field-name")
168
+ when Utilities.blank?(value)
123
169
  @name = name
124
- @value = nil
125
- @raw_value = nil
170
+ @unparsed_value = nil
126
171
  @charset = charset
127
- else # Field.new("field-name", "value")
172
+ else
128
173
  @name = name
129
- @value = value
130
- @raw_value = nil
174
+ @unparsed_value = value
131
175
  @charset = charset
132
176
  end
133
177
  @name = FIELD_NAME_MAP[@name.to_s.downcase] || @name
@@ -138,8 +182,7 @@ module Mail
138
182
  end
139
183
 
140
184
  def field
141
- _, @value = split(@raw_value) if @raw_value && !@value
142
- @field ||= create_field(@name, @value, @charset)
185
+ @field ||= create_field(@name, @unparsed_value, @charset)
143
186
  end
144
187
 
145
188
  def name
@@ -217,14 +260,26 @@ module Mail
217
260
 
218
261
  private
219
262
 
220
- def split(raw_field)
221
- match_data = Mail::Multibyte.mb_chars(raw_field).match(FIELD_SPLIT)
222
- [
223
- Mail::Multibyte.mb_chars(match_data[1].to_s).strip,
224
- Mail::Multibyte.mb_chars(match_data[2].to_s).strip.to_s
225
- ]
226
- rescue
227
- $stderr.puts "WARNING: Could not parse (and so ignoring) '#{raw_field}'"
263
+ def create_field(name, value, charset)
264
+ new_field(name, value, charset)
265
+ rescue Mail::Field::ParseError => e
266
+ field = Mail::UnstructuredField.new(name, value)
267
+ field.errors << [name, value, e]
268
+ field
269
+ end
270
+
271
+ def new_field(name, value, charset)
272
+ value = unfold(value) if value.is_a?(String)
273
+
274
+ if klass = field_class_for(name)
275
+ klass.new(value, charset)
276
+ else
277
+ OptionalField.new(name, value, charset)
278
+ end
279
+ end
280
+
281
+ def field_class_for(name)
282
+ FIELDS_MAP[name.to_s.downcase]
228
283
  end
229
284
 
230
285
  # 2.2.3. Long Header Fields
@@ -238,28 +293,5 @@ module Mail
238
293
  def unfold(string)
239
294
  string.gsub(/#{CRLF}(#{WSP})/m, '\1')
240
295
  end
241
-
242
- def create_field(name, value, charset)
243
- value = unfold(value) if value.is_a?(String)
244
-
245
- begin
246
- new_field(name, value, charset)
247
- rescue Mail::Field::ParseError => e
248
- field = Mail::UnstructuredField.new(name, value)
249
- field.errors << [name, value, e]
250
- field
251
- end
252
- end
253
-
254
- def new_field(name, value, charset)
255
- lower_case_name = name.to_s.downcase
256
- if field_klass = FIELDS_MAP[lower_case_name]
257
- field_klass.new(value, charset)
258
- else
259
- OptionalField.new(name, value, charset)
260
- end
261
- end
262
-
263
296
  end
264
-
265
297
  end
@@ -37,9 +37,9 @@ module Mail
37
37
  FIELD_NAME = 'bcc'
38
38
  CAPITALIZED_FIELD = 'Bcc'
39
39
 
40
- def initialize(value = '', charset = 'utf-8')
40
+ def initialize(value = nil, charset = 'utf-8')
41
41
  @charset = charset
42
- super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
42
+ super(CAPITALIZED_FIELD, value, charset)
43
43
  self
44
44
  end
45
45
 
@@ -39,7 +39,7 @@ module Mail
39
39
 
40
40
  def initialize(value = nil, charset = 'utf-8')
41
41
  self.charset = charset
42
- super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
42
+ super(CAPITALIZED_FIELD, value, charset)
43
43
  self
44
44
  end
45
45
 
@@ -33,7 +33,7 @@ module Mail
33
33
 
34
34
  def initialize(value = nil, charset = 'utf-8')
35
35
  @charset = charset
36
- super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value))
36
+ super(CAPITALIZED_FIELD, value)
37
37
  self.parse
38
38
  self
39
39
  end
@@ -4,7 +4,6 @@ require 'mail/fields/common/address_container'
4
4
 
5
5
  module Mail
6
6
  module CommonAddress # :nodoc:
7
-
8
7
  def parse(val = value)
9
8
  unless Utilities.blank?(val)
10
9
  @address_list = AddressList.new(encode_if_needed(val))
@@ -12,15 +11,22 @@ module Mail
12
11
  nil
13
12
  end
14
13
  end
15
-
14
+
16
15
  def charset
17
16
  @charset
18
17
  end
19
-
20
- def encode_if_needed(val)
21
- Encodings.address_encode(val, charset)
18
+
19
+ def encode_if_needed(val) #:nodoc:
20
+ # Need to join arrays of addresses into a single value
21
+ if val.kind_of?(Array)
22
+ val.compact.map { |a| encode_if_needed a }.join(', ')
23
+
24
+ # Pass through UTF-8; encode non-UTF-8.
25
+ else
26
+ utf8_if_needed(val) || Encodings.encode_non_usascii(val, charset)
27
+ end
22
28
  end
23
-
29
+
24
30
  # Allows you to iterate through each address object in the address_list
25
31
  def each
26
32
  address_list.addresses.each do |address|
@@ -98,7 +104,26 @@ module Mail
98
104
  end
99
105
 
100
106
  private
101
-
107
+
108
+ if 'string'.respond_to?(:encoding)
109
+ # Pass through UTF-8 addresses
110
+ def utf8_if_needed(val)
111
+ if charset =~ /\AUTF-?8\z/i
112
+ val
113
+ elsif val.encoding == Encoding::UTF_8
114
+ val
115
+ elsif (utf8 = val.dup.force_encoding(Encoding::UTF_8)).valid_encoding?
116
+ utf8
117
+ end
118
+ end
119
+ else
120
+ def utf8_if_needed(val)
121
+ if charset =~ /\AUTF-?8\z/i
122
+ val
123
+ end
124
+ end
125
+ end
126
+
102
127
  def do_encode(field_name)
103
128
  return '' if Utilities.blank?(value)
104
129
  address_array = address_list.addresses.reject { |a| encoded_group_addresses.include?(a.encoded) }.compact.map { |a| a.encoded }