Top Description Fields Constructors Methods
javax.mail.internet

public Class MimeUtility

Additional top-level class in compilation unit: AsciiOutputStream.

extends Object
Class Inheritance
Imports
javax.mail.MessagingException, .EncodingAware, javax.activation.*, java.util.*, java.io.*, java.nio.charset.Charset, com.sun.mail.util.PropUtil, .ASCIIUtility, .BASE64DecoderStream, .BASE64EncoderStream, .BEncoderStream, .LineInputStream, .LineOutputStream, .LogOutputStream, .QDecoderStream, .QEncoderStream, .QPDecoderStream, .QPEncoderStream, .UUDecoderStream, .UUEncoderStream

This is a utility class that provides various MIME related functionality.

There are a set of methods to encode and decode MIME headers as per RFC 2047. Note that, in general, these methods are not needed when using methods such as setSubject and setRecipients; JavaMail will automatically encode and decode data when using these "higher level" methods. The methods below are only needed when maniuplating raw MIME headers using setHeader and getHeader methods. A brief description on handling such headers is given below:

RFC 822 mail headers must contain only US-ASCII characters. Headers that contain non US-ASCII characters must be encoded so that they contain only US-ASCII characters. Basically, this process involves using either BASE64 or QP to encode certain characters. RFC 2047 describes this in detail.

In Java, Strings contain (16 bit) Unicode characters. ASCII is a subset of Unicode (and occupies the range 0 - 127). A String that contains only ASCII characters is already mail-safe. If the String contains non US-ASCII characters, it must be encoded. An additional complexity in this step is that since Unicode is not yet a widely used charset, one might want to first charset-encode the String into another charset and then do the transfer-encoding.

Note that to get the actual bytes of a mail-safe String (say, for sending over SMTP), one must do


	byte[] bytes = string.getBytes("iso-8859-1");	

 

The setHeader and addHeader methods on MimeMessage and MimeBodyPart assume that the given header values are Unicode strings that contain only US-ASCII characters. Hence the callers of those methods must insure that the values they pass do not contain non US-ASCII characters. The methods in this class help do this.

The getHeader family of methods on MimeMessage and MimeBodyPart return the raw header value. These might be encoded as per RFC 2047, and if so, must be decoded into Unicode Strings. The methods in this class help to do this.

Several System properties control strict conformance to the MIME spec. Note that these are not session properties but must be set globally as System properties.

The mail.mime.decodetext.strict property controls decoding of MIME encoded words. The MIME spec requires that encoded words start at the beginning of a whitespace separated word. Some mailers incorrectly include encoded words in the middle of a word. If the mail.mime.decodetext.strict System property is set to "false", an attempt will be made to decode these illegal encoded words. The default is true.

The mail.mime.encodeeol.strict property controls the choice of Content-Transfer-Encoding for MIME parts that are not of type "text". Often such parts will contain textual data for which an encoding that allows normal end of line conventions is appropriate. In rare cases, such a part will appear to contain entirely textual data, but will require an encoding that preserves CR and LF characters without change. If the mail.mime.encodeeol.strict System property is set to "true", such an encoding will be used when necessary. The default is false.

In addition, the mail.mime.charset System property can be used to specify the default MIME charset to use for encoded words and text parts that don't otherwise specify a charset. Normally, the default MIME charset is derived from the default Java charset, as specified in the file.encoding System property. Most applications will have no need to explicitly set the default MIME charset. In cases where the default MIME charset to be used for mail messages is different than the charset used for files stored on the system, this property should be set.

The current implementation also supports the following System property.

The mail.mime.ignoreunknownencoding property controls whether unknown values in the Content-Transfer-Encoding header, as passed to the decode method, cause an exception. If set to "true", unknown values are ignored and 8bit encoding is assumed. Otherwise, unknown values cause a MessagingException to be thrown.

Authors
John Mani, Bill Shannon

Field Summary

Modifier and TypeField and Description
public static final int
pack-priv static final int
private static final boolean
private static final boolean
private static String
private static String
private static final boolean
private static final boolean
private static final boolean
private static final boolean
private static Map<String, String>
private static Map<String, String>
pack-priv static final int
pack-priv static final int
private static final Map<String, Boolean>

Constructor Summary

AccessConstructor and Description
private

Method Summary

Modifier and TypeMethod and Description
pack-priv static int

Returns:

ALL_ASCII if all characters in the string belong to the US-ASCII charset. MOSTLY_ASCII if more than half of the available characters are US-ASCII characters. Else MOSTLY_NONASCII.
checkAscii
(String
string
s
)

Check if the given string contains non US-ASCII characters.

pack-priv static int

Returns:

ALL_ASCII if all characters in the string belong to the US-ASCII charset. MOSTLY_ASCII if more than half of the available characters are US-ASCII characters. Else MOSTLY_NONASCII. XXX - this method is no longer used
checkAscii
(byte[]
byte array
b
)

Check if the given byte array contains non US-ASCII characters.

pack-priv static int

Returns:

ALL_ASCII if all characters in the string belong to the US-ASCII charset. MOSTLY_ASCII if more than half of the available characters are US-ASCII characters. Else MOSTLY_NONASCII.
checkAscii
(InputStream
the input stream
is
,
int
maximum bytes to check for. The special value ALL indicates that all the bytes in this input stream must be checked.
max
,
boolean
if true, then terminate the the check when the first non-US-ASCII character is found.
breakOnNonAscii
)

Check if the given input stream contains non US-ASCII characters.

public static InputStream

Returns:

decoded input stream.
decode
(InputStream
input stream
is
,
String
the encoding of the stream.
encoding
)

Decode the given input stream.

private static String
decodeInnerWords(String word)

Look for encoded words within a word.

public static String

Returns:

the decoded text
decodeText
(String
the possibly encoded value
etext
)

Decode "unstructured" headers, that is, headers that are defined as '*text' as per RFC 822.

public static String

Returns:

the decoded word
decodeWord
(String
the encoded value
eword
)

The string is parsed using the rules in RFC 2047 and RFC 2231 for parsing an "encoded-word".

private static void
doEncode(String string, boolean b64, String jcharset, int avail, String prefix, boolean first, boolean encodingWord, StringBuilder buf)

public static OutputStream

Returns:

output stream that applies the specified encoding.
encode
(OutputStream
output stream
os
,
String
the encoding of the stream.
encoding
)

Wrap an encoder around the given output stream.

public static OutputStream

Returns:

output stream that applies the specified encoding.
encode
(OutputStream
output stream
os
,
String
the encoding of the stream.
encoding
,
String
name for the file being encoded (only used with uuencode)
filename
)

Wrap an encoder around the given output stream.

public static String

Returns:

Unicode string containing only US-ASCII characters
encodeText
(String
Unicode string
text
)

Encode a RFC 822 "text" token into mail-safe form as per RFC 2047.

public static String

Returns:

Unicode string containing only US-ASCII characters
encodeText
(String
the header value
text
,
String
the charset. If this parameter is null, the platform's default chatset is used.
charset
,
String
the encoding to be used. Currently supported values are "B" and "Q". If this parameter is null, then the "Q" encoding is used if most of characters to be encoded are in the ASCII charset, otherwise "B" encoding is used.
encoding
)

Encode a RFC 822 "text" token into mail-safe form as per RFC 2047.

public static String

Returns:

Array of Unicode strings containing only US-ASCII characters.
encodeWord
(String
Unicode string
word
)

Encode a RFC 822 "word" token into mail-safe form as per RFC 2047.

public static String

Returns:

Unicode string containing only US-ASCII characters
encodeWord
(String
Unicode string
word
,
String
the MIME charset
charset
,
String
the encoding to be used. Currently supported values are "B" and "Q". If this parameter is null, then the "Q" encoding is used if most of characters to be encoded are in the ASCII charset, otherwise "B" encoding is used.
encoding
)

Encode a RFC 822 "word" token into mail-safe form as per RFC 2047.

private static String
encodeWord(String string, String charset, String encoding, boolean encodingWord)

public static String

Returns:

the folded string
fold
(int
characters used in line so far
used
,
String
the string to fold
s
)

Fold a string at linear whitespace so that each line is no longer than 76 characters, if possible.

public static String

Returns:

the default charset of the system's default locale, as a Java charset. (NOT a MIME charset)
getDefaultJavaCharset
()

Get the default charset corresponding to the system's current default locale.

pack-priv static String
public static String

Returns:

the encoding. This is either "7bit", "quoted-printable" or "base64"
getEncoding
(DataSource
the DataSource
ds
)

Get the Content-Transfer-Encoding that should be applied to the input stream of this DataSource, to make it mail-safe.

public static String

Returns:

the Content-Transfer-Encoding
getEncoding
(DataHandler
the DataHandler
dh
)

Same as getEncoding(DataSource) except that instead of reading the data from an InputStream it uses the writeTo method to examine the data.

private static int
indexOfAny(String s, String any)

Return the first index of any of the characters in "any" in "s", or -1 if none are found.

private static int
indexOfAny(String s, String any, int start)

public static String

Returns:

the Java charset equivalent. If a suitable mapping is not available, the passed in charset is itself returned.
javaCharset
(String
the MIME charset name
charset
)

Convert a MIME charset name into a valid Java charset name.

private static void
private static String
makesafe(CharSequence s)

If the String or StringBuilder has any embedded newlines, make sure they're followed by whitespace, to prevent header injection errors.

public static String

Returns:

the MIME/IANA equivalent. If a mapping is not possible, the passed in charset itself is returned.
mimeCharset
(String
the JDK charset
charset
)

Convert a java charset into its MIME charset name.

pack-priv static final boolean
nonascii(int b)

private static boolean
nonAsciiCharset(ContentType ct)

Determine whether the charset in the Content-Type is compatible with ASCII or not.

public static String

Returns:

the possibly quoted word
quote
(String
word to be quoted
word
,
String
the set of special characters
specials
)

A utility method to quote a word, if the word contains any characters from the specified 'specials' list.

public static String

Returns:

the unfolded string
unfold
(String
the string to unfold
s
)

Unfold a folded header.

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

ALLback to summary
public static final int ALL
ALL_ASCIIback to summary
pack-priv static final int ALL_ASCII
allowUtf8back to summary
private static final boolean allowUtf8
decodeStrictback to summary
private static final boolean decodeStrict
defaultJavaCharsetback to summary
private static String defaultJavaCharset
defaultMIMECharsetback to summary
private static String defaultMIMECharset
encodeEolStrictback to summary
private static final boolean encodeEolStrict
foldEncodedWordsback to summary
private static final boolean foldEncodedWords
foldTextback to summary
private static final boolean foldText
ignoreUnknownEncodingback to summary
private static final boolean ignoreUnknownEncoding
java2mimeback to summary
private static Map<String, String> java2mime
mime2javaback to summary
private static Map<String, String> mime2java
MOSTLY_ASCIIback to summary
pack-priv static final int MOSTLY_ASCII
MOSTLY_NONASCIIback to summary
pack-priv static final int MOSTLY_NONASCII
nonAsciiCharsetMapback to summary
private static final Map<String, Boolean> nonAsciiCharsetMap

Constructor Detail

MimeUtilityback to summary
private MimeUtility()

Method Detail

checkAsciiback to summary
pack-priv static int checkAscii(String s)

Check if the given string contains non US-ASCII characters.

Parameters
s:String

string

Returns:int

ALL_ASCII if all characters in the string belong to the US-ASCII charset. MOSTLY_ASCII if more than half of the available characters are US-ASCII characters. Else MOSTLY_NONASCII.

checkAsciiback to summary
pack-priv static int checkAscii(byte[] b)

Check if the given byte array contains non US-ASCII characters.

Parameters
b:byte[]

byte array

Returns:int

ALL_ASCII if all characters in the string belong to the US-ASCII charset. MOSTLY_ASCII if more than half of the available characters are US-ASCII characters. Else MOSTLY_NONASCII. XXX - this method is no longer used

checkAsciiback to summary
pack-priv static int checkAscii(InputStream is, int max, boolean breakOnNonAscii)

Check if the given input stream contains non US-ASCII characters. Upto max bytes are checked. If max is set to ALL, then all the bytes available in this input stream are checked. If breakOnNonAscii is true the check terminates when the first non-US-ASCII character is found and MOSTLY_NONASCII is returned. Else, the check continues till max bytes or till the end of stream.

Parameters
is:InputStream

the input stream

max:int

maximum bytes to check for. The special value ALL indicates that all the bytes in this input stream must be checked.

breakOnNonAscii:boolean

if true, then terminate the the check when the first non-US-ASCII character is found.

Returns:int

ALL_ASCII if all characters in the string belong to the US-ASCII charset. MOSTLY_ASCII if more than half of the available characters are US-ASCII characters. Else MOSTLY_NONASCII.

decodeback to summary
public static InputStream decode(InputStream is, String encoding) throws MessagingException

Decode the given input stream. The Input stream returned is the decoded input stream. All the encodings defined in RFC 2045 are supported here. They include "base64", "quoted-printable", "7bit", "8bit", and "binary". In addition, "uuencode" is also supported.

In the current implementation, if the mail.mime.ignoreunknownencoding system property is set to "true", unknown encoding values are ignored and the original InputStream is returned.

Parameters
is:InputStream

input stream

encoding:String

the encoding of the stream.

Returns:InputStream

decoded input stream.

Exceptions
MessagingException:
if the encoding is unknown
decodeInnerWordsback to summary
private static String decodeInnerWords(String word) throws UnsupportedEncodingException

Look for encoded words within a word. The MIME spec doesn't allow this, but many broken mailers, especially Japanese mailers, produce such incorrect encodings.

decodeTextback to summary
public static String decodeText(String etext) throws UnsupportedEncodingException

Decode "unstructured" headers, that is, headers that are defined as '*text' as per RFC 822.

The string is decoded using the algorithm specified in RFC 2047, Section 6.1. If the charset-conversion fails for any sequence, an UnsupportedEncodingException is thrown. If the String is not an RFC 2047 style encoded header, it is returned as-is

Example of usage:


  MimePart part = ...
  String rawvalue = null;
  String  value = null;
  try {
    if ((rawvalue = part.getHeader("X-mailer")[0]) != null)
      value = MimeUtility.decodeText(rawvalue);
  } catch (UnsupportedEncodingException e) {
      // Don't care
      value = rawvalue;
  } catch (MessagingException me) { }

  return value;

 

Parameters
etext:String

the possibly encoded value

Returns:String

the decoded text

Exceptions
UnsupportedEncodingException:
if the charset conversion failed.
decodeWordback to summary
public static String decodeWord(String eword) throws ParseException, UnsupportedEncodingException

The string is parsed using the rules in RFC 2047 and RFC 2231 for parsing an "encoded-word". If the parse fails, a ParseException is thrown. Otherwise, it is transfer-decoded, and then charset-converted into Unicode. If the charset-conversion fails, an UnsupportedEncodingException is thrown.

Parameters
eword:String

the encoded value

Returns:String

the decoded word

Exceptions
ParseException:
if the string is not an encoded-word as per RFC 2047 and RFC 2231.
UnsupportedEncodingException:
if the charset conversion failed.
doEncodeback to summary
private static void doEncode(String string, boolean b64, String jcharset, int avail, String prefix, boolean first, boolean encodingWord, StringBuilder buf) throws UnsupportedEncodingException
encodeback to summary
public static OutputStream encode(OutputStream os, String encoding) throws MessagingException

Wrap an encoder around the given output stream. All the encodings defined in RFC 2045 are supported here. They include "base64", "quoted-printable", "7bit", "8bit" and "binary". In addition, "uuencode" is also supported.

Parameters
os:OutputStream

output stream

encoding:String

the encoding of the stream.

Returns:OutputStream

output stream that applies the specified encoding.

Exceptions
MessagingException:
if the encoding is unknown
encodeback to summary
public static OutputStream encode(OutputStream os, String encoding, String filename) throws MessagingException

Wrap an encoder around the given output stream. All the encodings defined in RFC 2045 are supported here. They include "base64", "quoted-printable", "7bit", "8bit" and "binary". In addition, "uuencode" is also supported. The filename parameter is used with the "uuencode" encoding and is included in the encoded output.

Parameters
os:OutputStream

output stream

encoding:String

the encoding of the stream.

filename:String

name for the file being encoded (only used with uuencode)

Returns:OutputStream

output stream that applies the specified encoding.

Exceptions
MessagingException:
for unknown encodings
Since
JavaMail 1.2
encodeTextback to summary
public static String encodeText(String text) throws UnsupportedEncodingException

Encode a RFC 822 "text" token into mail-safe form as per RFC 2047.

The given Unicode string is examined for non US-ASCII characters. If the string contains only US-ASCII characters, it is returned as-is. If the string contains non US-ASCII characters, it is first character-encoded using the platform's default charset, then transfer-encoded using either the B or Q encoding. The resulting bytes are then returned as a Unicode string containing only ASCII characters.

Note that this method should be used to encode only "unstructured" RFC 822 headers.

Example of usage:


 MimePart part = ...
 String rawvalue = "FooBar Mailer, Japanese version 1.1"
 try {
   // If we know for sure that rawvalue contains only US-ASCII 
   // characters, we can skip the encoding part
   part.setHeader("X-mailer", MimeUtility.encodeText(rawvalue));
 } catch (UnsupportedEncodingException e) {
   // encoding failure
 } catch (MessagingException me) {
  // setHeader() failure
 }

Parameters
text:String

Unicode string

Returns:String

Unicode string containing only US-ASCII characters

Exceptions
UnsupportedEncodingException:
if the encoding fails
encodeTextback to summary
public static String encodeText(String text, String charset, String encoding) throws UnsupportedEncodingException

Encode a RFC 822 "text" token into mail-safe form as per RFC 2047.

The given Unicode string is examined for non US-ASCII characters. If the string contains only US-ASCII characters, it is returned as-is. If the string contains non US-ASCII characters, it is first character-encoded using the specified charset, then transfer-encoded using either the B or Q encoding. The resulting bytes are then returned as a Unicode string containing only ASCII characters.

Note that this method should be used to encode only "unstructured" RFC 822 headers.

Parameters
text:String

the header value

charset:String

the charset. If this parameter is null, the platform's default chatset is used.

encoding:String

the encoding to be used. Currently supported values are "B" and "Q". If this parameter is null, then the "Q" encoding is used if most of characters to be encoded are in the ASCII charset, otherwise "B" encoding is used.

Returns:String

Unicode string containing only US-ASCII characters

Exceptions
UnsupportedEncodingException:
if the charset conversion failed.
encodeWordback to summary
public static String encodeWord(String word) throws UnsupportedEncodingException

Encode a RFC 822 "word" token into mail-safe form as per RFC 2047.

The given Unicode string is examined for non US-ASCII characters. If the string contains only US-ASCII characters, it is returned as-is. If the string contains non US-ASCII characters, it is first character-encoded using the platform's default charset, then transfer-encoded using either the B or Q encoding. The resulting bytes are then returned as a Unicode string containing only ASCII characters.

This method is meant to be used when creating RFC 822 "phrases". The InternetAddress class, for example, uses this to encode it's 'phrase' component.

Parameters
word:String

Unicode string

Returns:String

Array of Unicode strings containing only US-ASCII characters.

Exceptions
UnsupportedEncodingException:
if the encoding fails
encodeWordback to summary
public static String encodeWord(String word, String charset, String encoding) throws UnsupportedEncodingException

Encode a RFC 822 "word" token into mail-safe form as per RFC 2047.

The given Unicode string is examined for non US-ASCII characters. If the string contains only US-ASCII characters, it is returned as-is. If the string contains non US-ASCII characters, it is first character-encoded using the specified charset, then transfer-encoded using either the B or Q encoding. The resulting bytes are then returned as a Unicode string containing only ASCII characters.

Parameters
word:String

Unicode string

charset:String

the MIME charset

encoding:String

the encoding to be used. Currently supported values are "B" and "Q". If this parameter is null, then the "Q" encoding is used if most of characters to be encoded are in the ASCII charset, otherwise "B" encoding is used.

Returns:String

Unicode string containing only US-ASCII characters

Exceptions
UnsupportedEncodingException:
if the encoding fails
encodeWordback to summary
private static String encodeWord(String string, String charset, String encoding, boolean encodingWord) throws UnsupportedEncodingException
foldback to summary
public static String fold(int used, String s)

Fold a string at linear whitespace so that each line is no longer than 76 characters, if possible. If there are more than 76 non-whitespace characters consecutively, the string is folded at the first whitespace after that sequence. The parameter used indicates how many characters have been used in the current line; it is usually the length of the header name.

Note that line breaks in the string aren't escaped; they probably should be.

Parameters
used:int

characters used in line so far

s:String

the string to fold

Returns:String

the folded string

Since
JavaMail 1.4
getDefaultJavaCharsetback to summary
public static String getDefaultJavaCharset()

Get the default charset corresponding to the system's current default locale. If the System property mail.mime.charset is set, a system charset corresponding to this MIME charset will be returned.

Returns:String

the default charset of the system's default locale, as a Java charset. (NOT a MIME charset)

Since
JavaMail 1.1
getDefaultMIMECharsetback to summary
pack-priv static String getDefaultMIMECharset()
getEncodingback to summary
public static String getEncoding(DataSource ds)

Get the Content-Transfer-Encoding that should be applied to the input stream of this DataSource, to make it mail-safe.

The algorithm used here is:

  • If the DataSource implements EncodingAware, ask it what encoding to use. If it returns non-null, return that value.
  • If the primary type of this datasource is "text" and if all the bytes in its input stream are US-ASCII, then the encoding is "7bit". If more than half of the bytes are non-US-ASCII, then the encoding is "base64". If less than half of the bytes are non-US-ASCII, then the encoding is "quoted-printable".
  • If the primary type of this datasource is not "text", then if all the bytes of its input stream are US-ASCII, the encoding is "7bit". If there is even one non-US-ASCII character, the encoding is "base64".
Parameters
ds:DataSource

the DataSource

Returns:String

the encoding. This is either "7bit", "quoted-printable" or "base64"

getEncodingback to summary
public static String getEncoding(DataHandler dh)

Same as getEncoding(DataSource) except that instead of reading the data from an InputStream it uses the writeTo method to examine the data. This is more efficient in the common case of a DataHandler created with an object and a MIME type (for example, a "text/plain" String) because all the I/O is done in this thread. In the case requiring an InputStream the DataHandler uses a thread, a pair of pipe streams, and the writeTo method to produce the data.

Parameters
dh:DataHandler

the DataHandler

Returns:String

the Content-Transfer-Encoding

Since
JavaMail 1.2
indexOfAnyback to summary
private static int indexOfAny(String s, String any)

Return the first index of any of the characters in "any" in "s", or -1 if none are found. This should be a method on String.

indexOfAnyback to summary
private static int indexOfAny(String s, String any, int start)
javaCharsetback to summary
public static String javaCharset(String charset)

Convert a MIME charset name into a valid Java charset name.

Parameters
charset:String

the MIME charset name

Returns:String

the Java charset equivalent. If a suitable mapping is not available, the passed in charset is itself returned.

loadMappingsback to summary
private static void loadMappings(LineInputStream is, Map<String, String> table)
makesafeback to summary
private static String makesafe(CharSequence s)

If the String or StringBuilder has any embedded newlines, make sure they're followed by whitespace, to prevent header injection errors.

mimeCharsetback to summary
public static String mimeCharset(String charset)

Convert a java charset into its MIME charset name.

Note that a future version of JDK (post 1.2) might provide this functionality, in which case, we may deprecate this method then.

Parameters
charset:String

the JDK charset

Returns:String

the MIME/IANA equivalent. If a mapping is not possible, the passed in charset itself is returned.

Since
JavaMail 1.1
nonasciiback to summary
pack-priv static final boolean nonascii(int b)
nonAsciiCharsetback to summary
private static boolean nonAsciiCharset(ContentType ct)

Determine whether the charset in the Content-Type is compatible with ASCII or not. A charset is compatible with ASCII if the encoded byte stream representing the Unicode string "\r\n" is the ASCII characters CR and LF. For example, the utf-16be charset is not compatible with ASCII. For performance, we keep a static map that caches the results.

quoteback to summary
public static String quote(String word, String specials)

A utility method to quote a word, if the word contains any characters from the specified 'specials' list.

The HeaderTokenizer class defines two special sets of delimiters - MIME and RFC 822.

This method is typically used during the generation of RFC 822 and MIME header fields.

Parameters
word:String

word to be quoted

specials:String

the set of special characters

Returns:String

the possibly quoted word

See Also
javax.mail.internet.HeaderTokenizer#MIME, javax.mail.internet.HeaderTokenizer#RFC822
unfoldback to summary
public static String unfold(String s)

Unfold a folded header. Any line breaks that aren't escaped and are followed by whitespace are removed.

Parameters
s:String

the string to unfold

Returns:String

the unfolded string

Since
JavaMail 1.4