Module: Mail::Encodings

Extended by:
Utilities
Includes:
Constants
Defined in:
lib/mail/encodings.rb,
lib/mail/encodings/7bit.rb,
lib/mail/encodings/8bit.rb,
lib/mail/encodings/base64.rb,
lib/mail/encodings/binary.rb,
lib/mail/encodings/identity.rb,
lib/mail/encodings/unix_to_unix.rb,
lib/mail/encodings/quoted_printable.rb,
lib/mail/encodings/transfer_encoding.rb

Defined Under Namespace

Classes: Base64, Binary, EightBit, Identity, QuotedPrintable, SevenBit, TransferEncoding, UnixToUnix

Constant Summary

Constants included from Utilities

Utilities::TO_CRLF_REGEX

Constants included from Constants

Constants::ASTERISK, Constants::ATOM_UNSAFE, Constants::B_VALUES, Constants::CAPITAL_M, Constants::COLON, Constants::CONTROL_CHAR, Constants::CR, Constants::CRLF, Constants::CR_ENCODED, Constants::EMPTY, Constants::ENCODED_VALUE, Constants::EQUAL_LF, Constants::FIELD_BODY, Constants::FIELD_LINE, Constants::FIELD_NAME, Constants::FIELD_PREFIX, Constants::FIELD_SPLIT, Constants::FULL_ENCODED_VALUE, Constants::FWS, Constants::HEADER_LINE, Constants::HEADER_SPLIT, Constants::HYPHEN, Constants::LAX_CRLF, Constants::LF, Constants::LF_ENCODED, Constants::NULL_SENDER, Constants::PHRASE_UNSAFE, Constants::QP_SAFE, Constants::QP_UNSAFE, Constants::Q_VALUES, Constants::SPACE, Constants::TEXT, Constants::TOKEN_UNSAFE, Constants::UNDERSCORE, Constants::UNFOLD_WS, Constants::WSP

Class Method Summary collapse

Methods included from Utilities

atom_safe?, binary_unsafe_to_crlf, binary_unsafe_to_lf, blank?, bracket, bracket, capitalize_field, constantize, dasherize, decode_base64, decode_utf7, dquote, encode_base64, encode_utf7, escape_bracket, escape_paren, escape_paren, generate_message_id, get_constant, has_constant?, map_lines, map_with_index, match_to_s, paren, paren, pick_encoding, quote_atom, quote_phrase, quote_token, safe_for_line_ending_conversion?, string_byteslice, to_crlf, to_lf, token_safe?, unbracket, underscoreize, unescape, unparen, unquote, uri_escape, uri_parser, uri_parser, uri_unescape

Class Method Details

.address_encode(address, charset = 'utf-8') ⇒ Object



162
163
164
165
166
167
168
# File 'lib/mail/encodings.rb', line 162

def Encodings.address_encode(address, charset = 'utf-8')
  if address.is_a?(Array)
    address.compact.map { |a| Encodings.address_encode(a, charset) }.join(", ")
  elsif address
    encode_non_usascii(address, charset)
  end
end

.b_value_encode(string, encoding = nil) ⇒ Object

Encode a string with Base64 Encoding and returns it ready to be inserted as a value for a field, that is, in the =?<charset>?B?<string>?= format

Example:

Encodings.b_value_encode('This is あ string', 'UTF-8')
#=> "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?="


199
200
201
202
203
204
205
206
207
208
# File 'lib/mail/encodings.rb', line 199

def Encodings.b_value_encode(string, encoding = nil)
  if string.to_s.ascii_only?
    string
  else
    Encodings.each_base64_chunk_byterange(string, 60).map do |chunk|
      str, encoding = Utilities.b_value_encode(chunk, encoding)
      "=?#{encoding}?B?#{str.chomp}?="
    end.join(" ")
  end
end

.decode_encode(str, output_type) ⇒ Object

Decodes or encodes a string as needed for either Base64 or QP encoding types in the =?<encoding>??<string>?=“ format.

The output type needs to be :decode to decode the input string or :encode to encode the input string. The character set used for encoding will be the encoding on the string passed in.

On encoding, will only send out Base64 encoded strings.



105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/mail/encodings.rb', line 105

def Encodings.decode_encode(str, output_type)
  case
  when output_type == :decode
    Encodings.value_decode(str)
  else
    if str.ascii_only?
      str
    else
      Encodings.b_value_encode(str, str.encoding)
    end
  end
end

.defined?(name) ⇒ Boolean

Is the encoding we want defined?

Example:

Encodings.defined?(:base64) #=> true

Returns:

  • (Boolean)


29
30
31
# File 'lib/mail/encodings.rb', line 29

def Encodings.defined?(name)
  @transfer_encodings.include? get_name(name)
end

.encode_non_usascii(address, charset) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/mail/encodings.rb', line 170

def Encodings.encode_non_usascii(address, charset)
  return address if address.ascii_only? or charset.nil?

  # Encode all strings embedded inside of quotes
  address = address.gsub(/("[^"]*[^\/]")/) { |s| Encodings.b_value_encode(unquote(s), charset) }

  # Then loop through all remaining items and encode as needed
  tokens = address.split(/\s/)

  map_with_index(tokens) do |word, i|
    if word.ascii_only?
      word
    else
      previous_non_ascii = i>0 && tokens[i-1] && !tokens[i-1].ascii_only?
      if previous_non_ascii #why are we adding an extra space here?
        word = " #{word}"
      end
      Encodings.b_value_encode(word, charset)
    end
  end.join(' ')
end

.get_allObject



45
46
47
# File 'lib/mail/encodings.rb', line 45

def Encodings.get_all
  @transfer_encodings.values
end

.get_encoding(name) ⇒ Object

Gets a defined encoding type, QuotedPrintable or Base64 for now.

Each encoding needs to be defined as a Mail::Encodings::ClassName for this to work, allows us to add other encodings in the future.

Example:

Encodings.get_encoding(:base64) #=> Mail::Encodings::Base64


41
42
43
# File 'lib/mail/encodings.rb', line 41

def Encodings.get_encoding(name)
  @transfer_encodings[get_name(name)]
end

.get_name(name) ⇒ Object



49
50
51
# File 'lib/mail/encodings.rb', line 49

def Encodings.get_name(name)
  underscoreize(name).downcase
end

.param_decode(str, encoding) ⇒ Object

Decodes a parameter value using URI Escaping.

Example:

Mail::Encodings.param_decode("This%20is%20fun", 'us-ascii') #=> "This is fun"

str = Mail::Encodings.param_decode("This%20is%20fun", 'iso-8559-1')
str.encoding #=> 'ISO-8859-1'      ## Only on Ruby 1.9
str #=> "This is fun"


93
94
95
# File 'lib/mail/encodings.rb', line 93

def Encodings.param_decode(str, encoding)
  Utilities.param_decode(str, encoding)
end

.param_encode(str) ⇒ Object

Encodes a parameter value using URI Escaping, note the language field ‘en’ can be set using Mail::Configuration, like so:

Mail.defaults do
  param_encode_language 'jp'
end

The character set used for encoding will be the encoding on the string passed in.

Example:

Mail::Encodings.param_encode("This is fun") #=> "us-ascii'en'This%20is%20fun"


73
74
75
76
77
78
79
80
81
82
# File 'lib/mail/encodings.rb', line 73

def Encodings.param_encode(str)
  case
  when str.ascii_only? && str =~ TOKEN_UNSAFE
    %Q{"#{str}"}
  when str.ascii_only?
    str
  else
    Utilities.param_encode(str)
  end
end

.q_value_encode(encoded_str, encoding = nil) ⇒ Object

Encode a string with Quoted-Printable Encoding and returns it ready to be inserted as a value for a field, that is, in the =?<charset>?Q?<string>?= format

Example:

Encodings.q_value_encode('This is あ string', 'UTF-8')
#=> "=?UTF-8?Q?This_is_=E3=81=82_string?="


217
218
219
220
221
222
223
224
# File 'lib/mail/encodings.rb', line 217

def Encodings.q_value_encode(encoded_str, encoding = nil)
  return encoded_str if encoded_str.to_s.ascii_only?
  string, encoding = Utilities.q_value_encode(encoded_str, encoding)
  string.gsub!("=\r\n", '') # We already have limited the string to the length we want
  map_lines(string) do |str|
    "=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?="
  end.join(" ")
end

.register(name, cls) ⇒ Object

Register transfer encoding

Example

Encodings.register “base64”, Mail::Encodings::Base64



20
21
22
# File 'lib/mail/encodings.rb', line 20

def Encodings.register(name, cls)
  @transfer_encodings[get_name(name)] = cls
end

.transcode_charset(str, from_charset, to_charset = 'UTF-8') ⇒ Object



53
54
55
56
57
58
59
# File 'lib/mail/encodings.rb', line 53

def Encodings.transcode_charset(str, from_charset, to_charset = 'UTF-8')
  if from_charset
    Utilities.transcode_charset str, from_charset, to_charset
  else
    str
  end
end

.unquote_and_convert_to(str, to_encoding) ⇒ Object

Takes an encoded string of the format =?<encoding>??<string>?=



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/mail/encodings.rb', line 140

def Encodings.unquote_and_convert_to(str, to_encoding)
  output = value_decode( str ).to_s # output is already converted to UTF-8

  if 'utf8' == to_encoding.to_s.downcase.gsub("-", "")
    output
  elsif to_encoding
    begin
      output.encode(to_encoding)
    rescue Errno::EINVAL
      # the 'from' parameter specifies a charset other than what the text
      # actually is...not much we can do in this case but just return the
      # unconverted text.
      #
      # Ditto if either parameter represents an unknown charset, like
      # X-UNKNOWN.
      output
    end
  else
    output
  end
end

.value_decode(str) ⇒ Object

Decodes a given string as Base64 or Quoted Printable, depending on what type it is.

String has to be of the format =?<encoding>??<string>?=



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/mail/encodings.rb', line 122

def Encodings.value_decode(str)
  # Optimization: If there's no encoded-words in the string, just return it
  return str unless str =~ ENCODED_VALUE

  lines = collapse_adjacent_encodings(str)

  # Split on white-space boundaries with capture, so we capture the white-space as well
  lines.each do |line|
    line.gsub!(ENCODED_VALUE) do |string|
      case $2
      when *B_VALUES then b_value_decode(string)
      when *Q_VALUES then q_value_decode(string)
      end
    end
  end.join("")
end