/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.mail.javamail;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.activation.FileTypeMap;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimePart;
import javax.mail.internet.MimeUtility;
import org.springframework.core.io.InputStreamSource;
import org.springframework.core.io.Resource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
Helper class for populating a MimeMessage
. Mirrors the simple setters of SimpleMailMessage
, directly applying the values to the underlying MimeMessage. Allows for defining a character encoding for the entire message, automatically applied by all methods of this helper class.
Offers support for HTML text content, inline elements such as images, and typical
mail attachments. Also supports personal names that accompany mail addresses. Note that
advanced settings can still be applied directly to the underlying MimeMessage object!
Typically used in MimeMessagePreparator
implementations or JavaMailSender
client code: simply instantiating it as a MimeMessage wrapper, invoking setters on the wrapper, using the underlying MimeMessage for mail sending. Also used internally by JavaMailSenderImpl
.
Sample code for an HTML mail with an inline image and a PDF attachment:
mailSender.send(new MimeMessagePreparator() {
public void prepare(MimeMessage mimeMessage) throws MessagingException {
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, "UTF-8");
message.setFrom("me@mail.com");
message.setTo("you@mail.com");
message.setSubject("my subject");
message.setText("my text <img src='cid:myLogo'>", true);
message.addInline("myLogo", new ClassPathResource("img/mylogo.gif"));
message.addAttachment("myDocument.pdf", new ClassPathResource("doc/myDocument.pdf"));
}
});
Consider using MimeMailMessage
(which implements the common MailMessage
interface, just like SimpleMailMessage
) on top of this helper, in order to let message population code interact with a simple message or a MIME message through a common interface. Warning regarding multipart mails: Simple MIME messages that
just contain HTML text but no inline elements or attachments will work on
more or less any email client that is capable of HTML rendering. However,
inline elements and attachments are still a major compatibility issue
between email clients: It's virtually impossible to get inline elements
and attachments working across Microsoft Outlook, Lotus Notes and Mac Mail.
Consider choosing a specific multipart mode for your needs: The javadoc
on the MULTIPART_MODE constants contains more detailed information.
Author: Juergen Hoeller See Also: Since: 19.01.2004
/**
* Helper class for populating a {@link javax.mail.internet.MimeMessage}.
*
* <p>Mirrors the simple setters of {@link org.springframework.mail.SimpleMailMessage},
* directly applying the values to the underlying MimeMessage. Allows for defining
* a character encoding for the entire message, automatically applied by all methods
* of this helper class.
*
* <p>Offers support for HTML text content, inline elements such as images, and typical
* mail attachments. Also supports personal names that accompany mail addresses. Note that
* advanced settings can still be applied directly to the underlying MimeMessage object!
*
* <p>Typically used in {@link MimeMessagePreparator} implementations or
* {@link JavaMailSender} client code: simply instantiating it as a MimeMessage wrapper,
* invoking setters on the wrapper, using the underlying MimeMessage for mail sending.
* Also used internally by {@link JavaMailSenderImpl}.
*
* <p>Sample code for an HTML mail with an inline image and a PDF attachment:
*
* <pre class="code">
* mailSender.send(new MimeMessagePreparator() {
* public void prepare(MimeMessage mimeMessage) throws MessagingException {
* MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, "UTF-8");
* message.setFrom("me@mail.com");
* message.setTo("you@mail.com");
* message.setSubject("my subject");
* message.setText("my text <img src='cid:myLogo'>", true);
* message.addInline("myLogo", new ClassPathResource("img/mylogo.gif"));
* message.addAttachment("myDocument.pdf", new ClassPathResource("doc/myDocument.pdf"));
* }
* });</pre>
*
* Consider using {@link MimeMailMessage} (which implements the common
* {@link org.springframework.mail.MailMessage} interface, just like
* {@link org.springframework.mail.SimpleMailMessage}) on top of this helper,
* in order to let message population code interact with a simple message
* or a MIME message through a common interface.
*
* <p><b>Warning regarding multipart mails:</b> Simple MIME messages that
* just contain HTML text but no inline elements or attachments will work on
* more or less any email client that is capable of HTML rendering. However,
* inline elements and attachments are still a major compatibility issue
* between email clients: It's virtually impossible to get inline elements
* and attachments working across Microsoft Outlook, Lotus Notes and Mac Mail.
* Consider choosing a specific multipart mode for your needs: The javadoc
* on the MULTIPART_MODE constants contains more detailed information.
*
* @author Juergen Hoeller
* @since 19.01.2004
* @see #setText(String, boolean)
* @see #setText(String, String)
* @see #addInline(String, org.springframework.core.io.Resource)
* @see #addAttachment(String, org.springframework.core.io.InputStreamSource)
* @see #MULTIPART_MODE_MIXED_RELATED
* @see #MULTIPART_MODE_RELATED
* @see #getMimeMessage()
* @see JavaMailSender
*/
public class MimeMessageHelper {
Constant indicating a non-multipart message.
/**
* Constant indicating a non-multipart message.
*/
public static final int MULTIPART_MODE_NO = 0;
Constant indicating a multipart message with a single root multipart
element of type "mixed". Texts, inline elements and attachements
will all get added to that root element.
This was Spring 1.0's default behavior. It is known to work properly
on Outlook. However, other mail clients tend to misinterpret inline
elements as attachments and/or show attachments inline as well.
/**
* Constant indicating a multipart message with a single root multipart
* element of type "mixed". Texts, inline elements and attachements
* will all get added to that root element.
* <p>This was Spring 1.0's default behavior. It is known to work properly
* on Outlook. However, other mail clients tend to misinterpret inline
* elements as attachments and/or show attachments inline as well.
*/
public static final int MULTIPART_MODE_MIXED = 1;
Constant indicating a multipart message with a single root multipart
element of type "related". Texts, inline elements and attachements
will all get added to that root element.
This was the default behavior from Spring 1.1 up to 1.2 final.
This is the "Microsoft multipart mode", as natively sent by Outlook.
It is known to work properly on Outlook, Outlook Express, Yahoo Mail, and
to a large degree also on Mac Mail (with an additional attachment listed
for an inline element, despite the inline element also shown inline).
Does not work properly on Lotus Notes (attachments won't be shown there).
/**
* Constant indicating a multipart message with a single root multipart
* element of type "related". Texts, inline elements and attachements
* will all get added to that root element.
* <p>This was the default behavior from Spring 1.1 up to 1.2 final.
* This is the "Microsoft multipart mode", as natively sent by Outlook.
* It is known to work properly on Outlook, Outlook Express, Yahoo Mail, and
* to a large degree also on Mac Mail (with an additional attachment listed
* for an inline element, despite the inline element also shown inline).
* Does not work properly on Lotus Notes (attachments won't be shown there).
*/
public static final int MULTIPART_MODE_RELATED = 2;
Constant indicating a multipart message with a root multipart element
"mixed" plus a nested multipart element of type "related". Texts and
inline elements will get added to the nested "related" element,
while attachments will get added to the "mixed" root element.
This is the default since Spring 1.2.1. This is arguably the most correct
MIME structure, according to the MIME spec: It is known to work properly
on Outlook, Outlook Express, Yahoo Mail, and Lotus Notes. Does not work
properly on Mac Mail. If you target Mac Mail or experience issues with
specific mails on Outlook, consider using MULTIPART_MODE_RELATED instead.
/**
* Constant indicating a multipart message with a root multipart element
* "mixed" plus a nested multipart element of type "related". Texts and
* inline elements will get added to the nested "related" element,
* while attachments will get added to the "mixed" root element.
* <p>This is the default since Spring 1.2.1. This is arguably the most correct
* MIME structure, according to the MIME spec: It is known to work properly
* on Outlook, Outlook Express, Yahoo Mail, and Lotus Notes. Does not work
* properly on Mac Mail. If you target Mac Mail or experience issues with
* specific mails on Outlook, consider using MULTIPART_MODE_RELATED instead.
*/
public static final int MULTIPART_MODE_MIXED_RELATED = 3;
private static final String MULTIPART_SUBTYPE_MIXED = "mixed";
private static final String MULTIPART_SUBTYPE_RELATED = "related";
private static final String MULTIPART_SUBTYPE_ALTERNATIVE = "alternative";
private static final String CONTENT_TYPE_ALTERNATIVE = "text/alternative";
private static final String CONTENT_TYPE_HTML = "text/html";
private static final String CONTENT_TYPE_CHARSET_SUFFIX = ";charset=";
private static final String HEADER_PRIORITY = "X-Priority";
private static final String HEADER_CONTENT_ID = "Content-ID";
private final MimeMessage mimeMessage;
@Nullable
private MimeMultipart rootMimeMultipart;
@Nullable
private MimeMultipart mimeMultipart;
@Nullable
private final String encoding;
private FileTypeMap fileTypeMap;
private boolean validateAddresses = false;
Create a new MimeMessageHelper for the given MimeMessage,
assuming a simple text message (no multipart content,
i.e. no alternative texts and no inline elements or attachments).
The character encoding for the message will be taken from
the passed-in MimeMessage object, if carried there. Else,
JavaMail's default encoding will be used.
Params: - mimeMessage – the mime message to work on
See Also:
/**
* Create a new MimeMessageHelper for the given MimeMessage,
* assuming a simple text message (no multipart content,
* i.e. no alternative texts and no inline elements or attachments).
* <p>The character encoding for the message will be taken from
* the passed-in MimeMessage object, if carried there. Else,
* JavaMail's default encoding will be used.
* @param mimeMessage the mime message to work on
* @see #MimeMessageHelper(javax.mail.internet.MimeMessage, boolean)
* @see #getDefaultEncoding(javax.mail.internet.MimeMessage)
* @see JavaMailSenderImpl#setDefaultEncoding
*/
public MimeMessageHelper(MimeMessage mimeMessage) {
this(mimeMessage, null);
}
Create a new MimeMessageHelper for the given MimeMessage,
assuming a simple text message (no multipart content,
i.e. no alternative texts and no inline elements or attachments).
Params: - mimeMessage – the mime message to work on
- encoding – the character encoding to use for the message
See Also:
/**
* Create a new MimeMessageHelper for the given MimeMessage,
* assuming a simple text message (no multipart content,
* i.e. no alternative texts and no inline elements or attachments).
* @param mimeMessage the mime message to work on
* @param encoding the character encoding to use for the message
* @see #MimeMessageHelper(javax.mail.internet.MimeMessage, boolean)
*/
public MimeMessageHelper(MimeMessage mimeMessage, @Nullable String encoding) {
this.mimeMessage = mimeMessage;
this.encoding = (encoding != null ? encoding : getDefaultEncoding(mimeMessage));
this.fileTypeMap = getDefaultFileTypeMap(mimeMessage);
}
Create a new MimeMessageHelper for the given MimeMessage,
in multipart mode (supporting alternative texts, inline
elements and attachments) if requested.
Consider using the MimeMessageHelper constructor that
takes a multipartMode argument to choose a specific multipart
mode other than MULTIPART_MODE_MIXED_RELATED.
The character encoding for the message will be taken from
the passed-in MimeMessage object, if carried there. Else,
JavaMail's default encoding will be used.
Params: - mimeMessage – the mime message to work on
- multipart – whether to create a multipart message that
supports alternative texts, inline elements and attachments
(corresponds to MULTIPART_MODE_MIXED_RELATED)
Throws: - MessagingException – if multipart creation failed
See Also:
/**
* Create a new MimeMessageHelper for the given MimeMessage,
* in multipart mode (supporting alternative texts, inline
* elements and attachments) if requested.
* <p>Consider using the MimeMessageHelper constructor that
* takes a multipartMode argument to choose a specific multipart
* mode other than MULTIPART_MODE_MIXED_RELATED.
* <p>The character encoding for the message will be taken from
* the passed-in MimeMessage object, if carried there. Else,
* JavaMail's default encoding will be used.
* @param mimeMessage the mime message to work on
* @param multipart whether to create a multipart message that
* supports alternative texts, inline elements and attachments
* (corresponds to MULTIPART_MODE_MIXED_RELATED)
* @throws MessagingException if multipart creation failed
* @see #MimeMessageHelper(javax.mail.internet.MimeMessage, int)
* @see #getDefaultEncoding(javax.mail.internet.MimeMessage)
* @see JavaMailSenderImpl#setDefaultEncoding
*/
public MimeMessageHelper(MimeMessage mimeMessage, boolean multipart) throws MessagingException {
this(mimeMessage, multipart, null);
}
Create a new MimeMessageHelper for the given MimeMessage,
in multipart mode (supporting alternative texts, inline
elements and attachments) if requested.
Consider using the MimeMessageHelper constructor that
takes a multipartMode argument to choose a specific multipart
mode other than MULTIPART_MODE_MIXED_RELATED.
Params: - mimeMessage – the mime message to work on
- multipart – whether to create a multipart message that
supports alternative texts, inline elements and attachments
(corresponds to MULTIPART_MODE_MIXED_RELATED)
- encoding – the character encoding to use for the message
Throws: - MessagingException – if multipart creation failed
See Also:
/**
* Create a new MimeMessageHelper for the given MimeMessage,
* in multipart mode (supporting alternative texts, inline
* elements and attachments) if requested.
* <p>Consider using the MimeMessageHelper constructor that
* takes a multipartMode argument to choose a specific multipart
* mode other than MULTIPART_MODE_MIXED_RELATED.
* @param mimeMessage the mime message to work on
* @param multipart whether to create a multipart message that
* supports alternative texts, inline elements and attachments
* (corresponds to MULTIPART_MODE_MIXED_RELATED)
* @param encoding the character encoding to use for the message
* @throws MessagingException if multipart creation failed
* @see #MimeMessageHelper(javax.mail.internet.MimeMessage, int, String)
*/
public MimeMessageHelper(MimeMessage mimeMessage, boolean multipart, @Nullable String encoding)
throws MessagingException {
this(mimeMessage, (multipart ? MULTIPART_MODE_MIXED_RELATED : MULTIPART_MODE_NO), encoding);
}
Create a new MimeMessageHelper for the given MimeMessage,
in multipart mode (supporting alternative texts, inline
elements and attachments) if requested.
The character encoding for the message will be taken from
the passed-in MimeMessage object, if carried there. Else,
JavaMail's default encoding will be used.
Params: - mimeMessage – the mime message to work on
- multipartMode – which kind of multipart message to create
(MIXED, RELATED, MIXED_RELATED, or NO)
Throws: - MessagingException – if multipart creation failed
See Also:
/**
* Create a new MimeMessageHelper for the given MimeMessage,
* in multipart mode (supporting alternative texts, inline
* elements and attachments) if requested.
* <p>The character encoding for the message will be taken from
* the passed-in MimeMessage object, if carried there. Else,
* JavaMail's default encoding will be used.
* @param mimeMessage the mime message to work on
* @param multipartMode which kind of multipart message to create
* (MIXED, RELATED, MIXED_RELATED, or NO)
* @throws MessagingException if multipart creation failed
* @see #MULTIPART_MODE_NO
* @see #MULTIPART_MODE_MIXED
* @see #MULTIPART_MODE_RELATED
* @see #MULTIPART_MODE_MIXED_RELATED
* @see #getDefaultEncoding(javax.mail.internet.MimeMessage)
* @see JavaMailSenderImpl#setDefaultEncoding
*/
public MimeMessageHelper(MimeMessage mimeMessage, int multipartMode) throws MessagingException {
this(mimeMessage, multipartMode, null);
}
Create a new MimeMessageHelper for the given MimeMessage,
in multipart mode (supporting alternative texts, inline
elements and attachments) if requested.
Params: - mimeMessage – the mime message to work on
- multipartMode – which kind of multipart message to create
(MIXED, RELATED, MIXED_RELATED, or NO)
- encoding – the character encoding to use for the message
Throws: - MessagingException – if multipart creation failed
See Also:
/**
* Create a new MimeMessageHelper for the given MimeMessage,
* in multipart mode (supporting alternative texts, inline
* elements and attachments) if requested.
* @param mimeMessage the mime message to work on
* @param multipartMode which kind of multipart message to create
* (MIXED, RELATED, MIXED_RELATED, or NO)
* @param encoding the character encoding to use for the message
* @throws MessagingException if multipart creation failed
* @see #MULTIPART_MODE_NO
* @see #MULTIPART_MODE_MIXED
* @see #MULTIPART_MODE_RELATED
* @see #MULTIPART_MODE_MIXED_RELATED
*/
public MimeMessageHelper(MimeMessage mimeMessage, int multipartMode, @Nullable String encoding)
throws MessagingException {
this.mimeMessage = mimeMessage;
createMimeMultiparts(mimeMessage, multipartMode);
this.encoding = (encoding != null ? encoding : getDefaultEncoding(mimeMessage));
this.fileTypeMap = getDefaultFileTypeMap(mimeMessage);
}
Return the underlying MimeMessage object.
/**
* Return the underlying MimeMessage object.
*/
public final MimeMessage getMimeMessage() {
return this.mimeMessage;
}
Determine the MimeMultipart objects to use, which will be used
to store attachments on the one hand and text(s) and inline elements
on the other hand.
Texts and inline elements can either be stored in the root element
itself (MULTIPART_MODE_MIXED, MULTIPART_MODE_RELATED) or in a nested element
rather than the root element directly (MULTIPART_MODE_MIXED_RELATED).
By default, the root MimeMultipart element will be of type "mixed"
(MULTIPART_MODE_MIXED) or "related" (MULTIPART_MODE_RELATED).
The main multipart element will either be added as nested element of
type "related" (MULTIPART_MODE_MIXED_RELATED) or be identical to the root
element itself (MULTIPART_MODE_MIXED, MULTIPART_MODE_RELATED).
Params: - mimeMessage – the MimeMessage object to add the root MimeMultipart
object to
- multipartMode – the multipart mode, as passed into the constructor
(MIXED, RELATED, MIXED_RELATED, or NO)
Throws: - MessagingException – if multipart creation failed
See Also:
/**
* Determine the MimeMultipart objects to use, which will be used
* to store attachments on the one hand and text(s) and inline elements
* on the other hand.
* <p>Texts and inline elements can either be stored in the root element
* itself (MULTIPART_MODE_MIXED, MULTIPART_MODE_RELATED) or in a nested element
* rather than the root element directly (MULTIPART_MODE_MIXED_RELATED).
* <p>By default, the root MimeMultipart element will be of type "mixed"
* (MULTIPART_MODE_MIXED) or "related" (MULTIPART_MODE_RELATED).
* The main multipart element will either be added as nested element of
* type "related" (MULTIPART_MODE_MIXED_RELATED) or be identical to the root
* element itself (MULTIPART_MODE_MIXED, MULTIPART_MODE_RELATED).
* @param mimeMessage the MimeMessage object to add the root MimeMultipart
* object to
* @param multipartMode the multipart mode, as passed into the constructor
* (MIXED, RELATED, MIXED_RELATED, or NO)
* @throws MessagingException if multipart creation failed
* @see #setMimeMultiparts
* @see #MULTIPART_MODE_NO
* @see #MULTIPART_MODE_MIXED
* @see #MULTIPART_MODE_RELATED
* @see #MULTIPART_MODE_MIXED_RELATED
*/
protected void createMimeMultiparts(MimeMessage mimeMessage, int multipartMode) throws MessagingException {
switch (multipartMode) {
case MULTIPART_MODE_NO:
setMimeMultiparts(null, null);
break;
case MULTIPART_MODE_MIXED:
MimeMultipart mixedMultipart = new MimeMultipart(MULTIPART_SUBTYPE_MIXED);
mimeMessage.setContent(mixedMultipart);
setMimeMultiparts(mixedMultipart, mixedMultipart);
break;
case MULTIPART_MODE_RELATED:
MimeMultipart relatedMultipart = new MimeMultipart(MULTIPART_SUBTYPE_RELATED);
mimeMessage.setContent(relatedMultipart);
setMimeMultiparts(relatedMultipart, relatedMultipart);
break;
case MULTIPART_MODE_MIXED_RELATED:
MimeMultipart rootMixedMultipart = new MimeMultipart(MULTIPART_SUBTYPE_MIXED);
mimeMessage.setContent(rootMixedMultipart);
MimeMultipart nestedRelatedMultipart = new MimeMultipart(MULTIPART_SUBTYPE_RELATED);
MimeBodyPart relatedBodyPart = new MimeBodyPart();
relatedBodyPart.setContent(nestedRelatedMultipart);
rootMixedMultipart.addBodyPart(relatedBodyPart);
setMimeMultiparts(rootMixedMultipart, nestedRelatedMultipart);
break;
default:
throw new IllegalArgumentException("Only multipart modes MIXED_RELATED, RELATED and NO supported");
}
}
Set the given MimeMultipart objects for use by this MimeMessageHelper.
Params: - root – the root MimeMultipart object, which attachments will be added to; or
null
to indicate no multipart at all - main – the main MimeMultipart object, which text(s) and inline elements
will be added to (can be the same as the root multipart object, or an element
nested underneath the root multipart element)
/**
* Set the given MimeMultipart objects for use by this MimeMessageHelper.
* @param root the root MimeMultipart object, which attachments will be added to;
* or {@code null} to indicate no multipart at all
* @param main the main MimeMultipart object, which text(s) and inline elements
* will be added to (can be the same as the root multipart object, or an element
* nested underneath the root multipart element)
*/
protected final void setMimeMultiparts(@Nullable MimeMultipart root, @Nullable MimeMultipart main) {
this.rootMimeMultipart = root;
this.mimeMultipart = main;
}
Return whether this helper is in multipart mode,
i.e. whether it holds a multipart message.
See Also: - MimeMessageHelper(MimeMessage, boolean)
/**
* Return whether this helper is in multipart mode,
* i.e. whether it holds a multipart message.
* @see #MimeMessageHelper(MimeMessage, boolean)
*/
public final boolean isMultipart() {
return (this.rootMimeMultipart != null);
}
Return the root MIME "multipart/mixed" object, if any.
Can be used to manually add attachments.
This will be the direct content of the MimeMessage,
in case of a multipart mail.
Throws: - IllegalStateException – if this helper is not in multipart mode
See Also:
/**
* Return the root MIME "multipart/mixed" object, if any.
* Can be used to manually add attachments.
* <p>This will be the direct content of the MimeMessage,
* in case of a multipart mail.
* @throws IllegalStateException if this helper is not in multipart mode
* @see #isMultipart
* @see #getMimeMessage
* @see javax.mail.internet.MimeMultipart#addBodyPart
*/
public final MimeMultipart getRootMimeMultipart() throws IllegalStateException {
if (this.rootMimeMultipart == null) {
throw new IllegalStateException("Not in multipart mode - " +
"create an appropriate MimeMessageHelper via a constructor that takes a 'multipart' flag " +
"if you need to set alternative texts or add inline elements or attachments.");
}
return this.rootMimeMultipart;
}
Return the underlying MIME "multipart/related" object, if any.
Can be used to manually add body parts, inline elements, etc.
This will be nested within the root MimeMultipart,
in case of a multipart mail.
Throws: - IllegalStateException – if this helper is not in multipart mode
See Also:
/**
* Return the underlying MIME "multipart/related" object, if any.
* Can be used to manually add body parts, inline elements, etc.
* <p>This will be nested within the root MimeMultipart,
* in case of a multipart mail.
* @throws IllegalStateException if this helper is not in multipart mode
* @see #isMultipart
* @see #getRootMimeMultipart
* @see javax.mail.internet.MimeMultipart#addBodyPart
*/
public final MimeMultipart getMimeMultipart() throws IllegalStateException {
if (this.mimeMultipart == null) {
throw new IllegalStateException("Not in multipart mode - " +
"create an appropriate MimeMessageHelper via a constructor that takes a 'multipart' flag " +
"if you need to set alternative texts or add inline elements or attachments.");
}
return this.mimeMultipart;
}
Determine the default encoding for the given MimeMessage.
Params: - mimeMessage – the passed-in MimeMessage
Returns: the default encoding associated with the MimeMessage, or null
if none found
/**
* Determine the default encoding for the given MimeMessage.
* @param mimeMessage the passed-in MimeMessage
* @return the default encoding associated with the MimeMessage,
* or {@code null} if none found
*/
@Nullable
protected String getDefaultEncoding(MimeMessage mimeMessage) {
if (mimeMessage instanceof SmartMimeMessage) {
return ((SmartMimeMessage) mimeMessage).getDefaultEncoding();
}
return null;
}
Return the specific character encoding used for this message, if any.
/**
* Return the specific character encoding used for this message, if any.
*/
@Nullable
public String getEncoding() {
return this.encoding;
}
Determine the default Java Activation FileTypeMap for the given MimeMessage.
Params: - mimeMessage – the passed-in MimeMessage
See Also: Returns: the default FileTypeMap associated with the MimeMessage,
or a default ConfigurableMimeFileTypeMap if none found for the message
/**
* Determine the default Java Activation FileTypeMap for the given MimeMessage.
* @param mimeMessage the passed-in MimeMessage
* @return the default FileTypeMap associated with the MimeMessage,
* or a default ConfigurableMimeFileTypeMap if none found for the message
* @see ConfigurableMimeFileTypeMap
*/
protected FileTypeMap getDefaultFileTypeMap(MimeMessage mimeMessage) {
if (mimeMessage instanceof SmartMimeMessage) {
FileTypeMap fileTypeMap = ((SmartMimeMessage) mimeMessage).getDefaultFileTypeMap();
if (fileTypeMap != null) {
return fileTypeMap;
}
}
ConfigurableMimeFileTypeMap fileTypeMap = new ConfigurableMimeFileTypeMap();
fileTypeMap.afterPropertiesSet();
return fileTypeMap;
}
Set the Java Activation Framework FileTypeMap
to use for determining the content type of inline content and attachments that get added to the message. Default is the FileTypeMap
that the underlying MimeMessage carries, if any, or the Activation Framework's default FileTypeMap
instance else.
See Also:
/**
* Set the Java Activation Framework {@code FileTypeMap} to use
* for determining the content type of inline content and attachments
* that get added to the message.
* <p>Default is the {@code FileTypeMap} that the underlying
* MimeMessage carries, if any, or the Activation Framework's default
* {@code FileTypeMap} instance else.
* @see #addInline
* @see #addAttachment
* @see #getDefaultFileTypeMap(javax.mail.internet.MimeMessage)
* @see JavaMailSenderImpl#setDefaultFileTypeMap
* @see javax.activation.FileTypeMap#getDefaultFileTypeMap
* @see ConfigurableMimeFileTypeMap
*/
public void setFileTypeMap(@Nullable FileTypeMap fileTypeMap) {
this.fileTypeMap = (fileTypeMap != null ? fileTypeMap : getDefaultFileTypeMap(getMimeMessage()));
}
Return the FileTypeMap
used by this MimeMessageHelper. /**
* Return the {@code FileTypeMap} used by this MimeMessageHelper.
*/
public FileTypeMap getFileTypeMap() {
return this.fileTypeMap;
}
Set whether to validate all addresses which get passed to this helper.
Default is "false".
Note that this is by default just available for JavaMail >= 1.3. You can override the default validateAddress method
for validation on older JavaMail versions (or for custom validation).
See Also:
/**
* Set whether to validate all addresses which get passed to this helper.
* Default is "false".
* <p>Note that this is by default just available for JavaMail >= 1.3.
* You can override the default {@code validateAddress method} for
* validation on older JavaMail versions (or for custom validation).
* @see #validateAddress
*/
public void setValidateAddresses(boolean validateAddresses) {
this.validateAddresses = validateAddresses;
}
Return whether this helper will validate all addresses passed to it.
/**
* Return whether this helper will validate all addresses passed to it.
*/
public boolean isValidateAddresses() {
return this.validateAddresses;
}
Validate the given mail address.
Called by all of MimeMessageHelper's address setters and adders.
Default implementation invokes InternetAddress.validate()
, provided that address validation is activated for the helper instance.
Note that this method will just work on JavaMail >= 1.3. You can override
it for validation on older JavaMail versions or for custom validation.
Params: - address – the address to validate
Throws: - AddressException – if validation failed
See Also:
/**
* Validate the given mail address.
* Called by all of MimeMessageHelper's address setters and adders.
* <p>Default implementation invokes {@code InternetAddress.validate()},
* provided that address validation is activated for the helper instance.
* <p>Note that this method will just work on JavaMail >= 1.3. You can override
* it for validation on older JavaMail versions or for custom validation.
* @param address the address to validate
* @throws AddressException if validation failed
* @see #isValidateAddresses()
* @see javax.mail.internet.InternetAddress#validate()
*/
protected void validateAddress(InternetAddress address) throws AddressException {
if (isValidateAddresses()) {
address.validate();
}
}
Validate all given mail addresses.
Default implementation simply delegates to validateAddress for each address.
Params: - addresses – the addresses to validate
Throws: - AddressException – if validation failed
See Also:
/**
* Validate all given mail addresses.
* Default implementation simply delegates to validateAddress for each address.
* @param addresses the addresses to validate
* @throws AddressException if validation failed
* @see #validateAddress(InternetAddress)
*/
protected void validateAddresses(InternetAddress[] addresses) throws AddressException {
for (InternetAddress address : addresses) {
validateAddress(address);
}
}
public void setFrom(InternetAddress from) throws MessagingException {
Assert.notNull(from, "From address must not be null");
validateAddress(from);
this.mimeMessage.setFrom(from);
}
public void setFrom(String from) throws MessagingException {
Assert.notNull(from, "From address must not be null");
setFrom(parseAddress(from));
}
public void setFrom(String from, String personal) throws MessagingException, UnsupportedEncodingException {
Assert.notNull(from, "From address must not be null");
setFrom(getEncoding() != null ?
new InternetAddress(from, personal, getEncoding()) : new InternetAddress(from, personal));
}
public void setReplyTo(InternetAddress replyTo) throws MessagingException {
Assert.notNull(replyTo, "Reply-to address must not be null");
validateAddress(replyTo);
this.mimeMessage.setReplyTo(new InternetAddress[] {replyTo});
}
public void setReplyTo(String replyTo) throws MessagingException {
Assert.notNull(replyTo, "Reply-to address must not be null");
setReplyTo(parseAddress(replyTo));
}
public void setReplyTo(String replyTo, String personal) throws MessagingException, UnsupportedEncodingException {
Assert.notNull(replyTo, "Reply-to address must not be null");
InternetAddress replyToAddress = (getEncoding() != null) ?
new InternetAddress(replyTo, personal, getEncoding()) : new InternetAddress(replyTo, personal);
setReplyTo(replyToAddress);
}
public void setTo(InternetAddress to) throws MessagingException {
Assert.notNull(to, "To address must not be null");
validateAddress(to);
this.mimeMessage.setRecipient(Message.RecipientType.TO, to);
}
public void setTo(InternetAddress[] to) throws MessagingException {
Assert.notNull(to, "To address array must not be null");
validateAddresses(to);
this.mimeMessage.setRecipients(Message.RecipientType.TO, to);
}
public void setTo(String to) throws MessagingException {
Assert.notNull(to, "To address must not be null");
setTo(parseAddress(to));
}
public void setTo(String[] to) throws MessagingException {
Assert.notNull(to, "To address array must not be null");
InternetAddress[] addresses = new InternetAddress[to.length];
for (int i = 0; i < to.length; i++) {
addresses[i] = parseAddress(to[i]);
}
setTo(addresses);
}
public void addTo(InternetAddress to) throws MessagingException {
Assert.notNull(to, "To address must not be null");
validateAddress(to);
this.mimeMessage.addRecipient(Message.RecipientType.TO, to);
}
public void addTo(String to) throws MessagingException {
Assert.notNull(to, "To address must not be null");
addTo(parseAddress(to));
}
public void addTo(String to, String personal) throws MessagingException, UnsupportedEncodingException {
Assert.notNull(to, "To address must not be null");
addTo(getEncoding() != null ?
new InternetAddress(to, personal, getEncoding()) :
new InternetAddress(to, personal));
}
public void setCc(InternetAddress cc) throws MessagingException {
Assert.notNull(cc, "Cc address must not be null");
validateAddress(cc);
this.mimeMessage.setRecipient(Message.RecipientType.CC, cc);
}
public void setCc(InternetAddress[] cc) throws MessagingException {
Assert.notNull(cc, "Cc address array must not be null");
validateAddresses(cc);
this.mimeMessage.setRecipients(Message.RecipientType.CC, cc);
}
public void setCc(String cc) throws MessagingException {
Assert.notNull(cc, "Cc address must not be null");
setCc(parseAddress(cc));
}
public void setCc(String[] cc) throws MessagingException {
Assert.notNull(cc, "Cc address array must not be null");
InternetAddress[] addresses = new InternetAddress[cc.length];
for (int i = 0; i < cc.length; i++) {
addresses[i] = parseAddress(cc[i]);
}
setCc(addresses);
}
public void addCc(InternetAddress cc) throws MessagingException {
Assert.notNull(cc, "Cc address must not be null");
validateAddress(cc);
this.mimeMessage.addRecipient(Message.RecipientType.CC, cc);
}
public void addCc(String cc) throws MessagingException {
Assert.notNull(cc, "Cc address must not be null");
addCc(parseAddress(cc));
}
public void addCc(String cc, String personal) throws MessagingException, UnsupportedEncodingException {
Assert.notNull(cc, "Cc address must not be null");
addCc(getEncoding() != null ?
new InternetAddress(cc, personal, getEncoding()) :
new InternetAddress(cc, personal));
}
public void setBcc(InternetAddress bcc) throws MessagingException {
Assert.notNull(bcc, "Bcc address must not be null");
validateAddress(bcc);
this.mimeMessage.setRecipient(Message.RecipientType.BCC, bcc);
}
public void setBcc(InternetAddress[] bcc) throws MessagingException {
Assert.notNull(bcc, "Bcc address array must not be null");
validateAddresses(bcc);
this.mimeMessage.setRecipients(Message.RecipientType.BCC, bcc);
}
public void setBcc(String bcc) throws MessagingException {
Assert.notNull(bcc, "Bcc address must not be null");
setBcc(parseAddress(bcc));
}
public void setBcc(String[] bcc) throws MessagingException {
Assert.notNull(bcc, "Bcc address array must not be null");
InternetAddress[] addresses = new InternetAddress[bcc.length];
for (int i = 0; i < bcc.length; i++) {
addresses[i] = parseAddress(bcc[i]);
}
setBcc(addresses);
}
public void addBcc(InternetAddress bcc) throws MessagingException {
Assert.notNull(bcc, "Bcc address must not be null");
validateAddress(bcc);
this.mimeMessage.addRecipient(Message.RecipientType.BCC, bcc);
}
public void addBcc(String bcc) throws MessagingException {
Assert.notNull(bcc, "Bcc address must not be null");
addBcc(parseAddress(bcc));
}
public void addBcc(String bcc, String personal) throws MessagingException, UnsupportedEncodingException {
Assert.notNull(bcc, "Bcc address must not be null");
addBcc(getEncoding() != null ?
new InternetAddress(bcc, personal, getEncoding()) :
new InternetAddress(bcc, personal));
}
private InternetAddress parseAddress(String address) throws MessagingException {
InternetAddress[] parsed = InternetAddress.parse(address);
if (parsed.length != 1) {
throw new AddressException("Illegal address", address);
}
InternetAddress raw = parsed[0];
try {
return (getEncoding() != null ?
new InternetAddress(raw.getAddress(), raw.getPersonal(), getEncoding()) : raw);
}
catch (UnsupportedEncodingException ex) {
throw new MessagingException("Failed to parse embedded personal name to correct encoding", ex);
}
}
Set the priority ("X-Priority" header) of the message.
Params: - priority – the priority value;
typically between 1 (highest) and 5 (lowest)
Throws: - MessagingException – in case of errors
/**
* Set the priority ("X-Priority" header) of the message.
* @param priority the priority value;
* typically between 1 (highest) and 5 (lowest)
* @throws MessagingException in case of errors
*/
public void setPriority(int priority) throws MessagingException {
this.mimeMessage.setHeader(HEADER_PRIORITY, Integer.toString(priority));
}
Set the sent-date of the message.
Params: - sentDate – the date to set (never
null
)
Throws: - MessagingException – in case of errors
/**
* Set the sent-date of the message.
* @param sentDate the date to set (never {@code null})
* @throws MessagingException in case of errors
*/
public void setSentDate(Date sentDate) throws MessagingException {
Assert.notNull(sentDate, "Sent date must not be null");
this.mimeMessage.setSentDate(sentDate);
}
Set the subject of the message, using the correct encoding.
Params: - subject – the subject text
Throws: - MessagingException – in case of errors
/**
* Set the subject of the message, using the correct encoding.
* @param subject the subject text
* @throws MessagingException in case of errors
*/
public void setSubject(String subject) throws MessagingException {
Assert.notNull(subject, "Subject must not be null");
if (getEncoding() != null) {
this.mimeMessage.setSubject(subject, getEncoding());
}
else {
this.mimeMessage.setSubject(subject);
}
}
Set the given text directly as content in non-multipart mode
or as default body part in multipart mode.
Always applies the default content type "text/plain".
NOTE: Invoke addInline
after setText
; else, mail readers might not be able to resolve inline references correctly.
Params: - text – the text for the message
Throws: - MessagingException – in case of errors
/**
* Set the given text directly as content in non-multipart mode
* or as default body part in multipart mode.
* Always applies the default content type "text/plain".
* <p><b>NOTE:</b> Invoke {@link #addInline} <i>after</i> {@code setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param text the text for the message
* @throws MessagingException in case of errors
*/
public void setText(String text) throws MessagingException {
setText(text, false);
}
Set the given text directly as content in non-multipart mode
or as default body part in multipart mode.
The "html" flag determines the content type to apply.
NOTE: Invoke addInline
after setText
; else, mail readers might not be able to resolve inline references correctly.
Params: - text – the text for the message
- html – whether to apply content type "text/html" for an
HTML mail, using default content type ("text/plain") else
Throws: - MessagingException – in case of errors
/**
* Set the given text directly as content in non-multipart mode
* or as default body part in multipart mode.
* The "html" flag determines the content type to apply.
* <p><b>NOTE:</b> Invoke {@link #addInline} <i>after</i> {@code setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param text the text for the message
* @param html whether to apply content type "text/html" for an
* HTML mail, using default content type ("text/plain") else
* @throws MessagingException in case of errors
*/
public void setText(String text, boolean html) throws MessagingException {
Assert.notNull(text, "Text must not be null");
MimePart partToUse;
if (isMultipart()) {
partToUse = getMainPart();
}
else {
partToUse = this.mimeMessage;
}
if (html) {
setHtmlTextToMimePart(partToUse, text);
}
else {
setPlainTextToMimePart(partToUse, text);
}
}
Set the given plain text and HTML text as alternatives, offering
both options to the email client. Requires multipart mode.
NOTE: Invoke addInline
after setText
; else, mail readers might not be able to resolve inline references correctly.
Params: - plainText – the plain text for the message
- htmlText – the HTML text for the message
Throws: - MessagingException – in case of errors
/**
* Set the given plain text and HTML text as alternatives, offering
* both options to the email client. Requires multipart mode.
* <p><b>NOTE:</b> Invoke {@link #addInline} <i>after</i> {@code setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param plainText the plain text for the message
* @param htmlText the HTML text for the message
* @throws MessagingException in case of errors
*/
public void setText(String plainText, String htmlText) throws MessagingException {
Assert.notNull(plainText, "Plain text must not be null");
Assert.notNull(htmlText, "HTML text must not be null");
MimeMultipart messageBody = new MimeMultipart(MULTIPART_SUBTYPE_ALTERNATIVE);
getMainPart().setContent(messageBody, CONTENT_TYPE_ALTERNATIVE);
// Create the plain text part of the message.
MimeBodyPart plainTextPart = new MimeBodyPart();
setPlainTextToMimePart(plainTextPart, plainText);
messageBody.addBodyPart(plainTextPart);
// Create the HTML text part of the message.
MimeBodyPart htmlTextPart = new MimeBodyPart();
setHtmlTextToMimePart(htmlTextPart, htmlText);
messageBody.addBodyPart(htmlTextPart);
}
private MimeBodyPart getMainPart() throws MessagingException {
MimeMultipart mimeMultipart = getMimeMultipart();
MimeBodyPart bodyPart = null;
for (int i = 0; i < mimeMultipart.getCount(); i++) {
BodyPart bp = mimeMultipart.getBodyPart(i);
if (bp.getFileName() == null) {
bodyPart = (MimeBodyPart) bp;
}
}
if (bodyPart == null) {
MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeMultipart.addBodyPart(mimeBodyPart);
bodyPart = mimeBodyPart;
}
return bodyPart;
}
private void setPlainTextToMimePart(MimePart mimePart, String text) throws MessagingException {
if (getEncoding() != null) {
mimePart.setText(text, getEncoding());
}
else {
mimePart.setText(text);
}
}
private void setHtmlTextToMimePart(MimePart mimePart, String text) throws MessagingException {
if (getEncoding() != null) {
mimePart.setContent(text, CONTENT_TYPE_HTML + CONTENT_TYPE_CHARSET_SUFFIX + getEncoding());
}
else {
mimePart.setContent(text, CONTENT_TYPE_HTML);
}
}
Add an inline element to the MimeMessage, taking the content from a javax.activation.DataSource
. Note that the InputStream returned by the DataSource implementation
needs to be a fresh one on each call, as JavaMail will invoke getInputStream()
multiple times.
NOTE: Invoke addInline
after setText
; else, mail readers might not be able to resolve inline references correctly.
Params: - contentId – the content ID to use. Will end up as "Content-ID" header
in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
Can be referenced in HTML source via src="cid:myId" expressions.
- dataSource – the
javax.activation.DataSource
to take the content from, determining the InputStream and the content type
Throws: - MessagingException – in case of errors
See Also:
/**
* Add an inline element to the MimeMessage, taking the content from a
* {@code javax.activation.DataSource}.
* <p>Note that the InputStream returned by the DataSource implementation
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
* {@code getInputStream()} multiple times.
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@link #setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param contentId the content ID to use. Will end up as "Content-ID" header
* in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
* Can be referenced in HTML source via src="cid:myId" expressions.
* @param dataSource the {@code javax.activation.DataSource} to take
* the content from, determining the InputStream and the content type
* @throws MessagingException in case of errors
* @see #addInline(String, java.io.File)
* @see #addInline(String, org.springframework.core.io.Resource)
*/
public void addInline(String contentId, DataSource dataSource) throws MessagingException {
Assert.notNull(contentId, "Content ID must not be null");
Assert.notNull(dataSource, "DataSource must not be null");
MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setDisposition(MimeBodyPart.INLINE);
// We're using setHeader here to remain compatible with JavaMail 1.2,
// rather than JavaMail 1.3's setContentID.
mimeBodyPart.setHeader(HEADER_CONTENT_ID, "<" + contentId + ">");
mimeBodyPart.setDataHandler(new DataHandler(dataSource));
getMimeMultipart().addBodyPart(mimeBodyPart);
}
Add an inline element to the MimeMessage, taking the content from a java.io.File
. The content type will be determined by the name of the given
content file. Do not use this for temporary files with arbitrary
filenames (possibly ending in ".tmp" or the like)!
NOTE: Invoke addInline
after setText
; else, mail readers might not be able to resolve inline references correctly.
Params: - contentId – the content ID to use. Will end up as "Content-ID" header
in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
Can be referenced in HTML source via src="cid:myId" expressions.
- file – the File resource to take the content from
Throws: - MessagingException – in case of errors
See Also:
/**
* Add an inline element to the MimeMessage, taking the content from a
* {@code java.io.File}.
* <p>The content type will be determined by the name of the given
* content file. Do not use this for temporary files with arbitrary
* filenames (possibly ending in ".tmp" or the like)!
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@link #setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param contentId the content ID to use. Will end up as "Content-ID" header
* in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
* Can be referenced in HTML source via src="cid:myId" expressions.
* @param file the File resource to take the content from
* @throws MessagingException in case of errors
* @see #setText
* @see #addInline(String, org.springframework.core.io.Resource)
* @see #addInline(String, javax.activation.DataSource)
*/
public void addInline(String contentId, File file) throws MessagingException {
Assert.notNull(file, "File must not be null");
FileDataSource dataSource = new FileDataSource(file);
dataSource.setFileTypeMap(getFileTypeMap());
addInline(contentId, dataSource);
}
Add an inline element to the MimeMessage, taking the content from a org.springframework.core.io.Resource
. The content type will be determined by the name of the given
content file. Do not use this for temporary files with arbitrary
filenames (possibly ending in ".tmp" or the like)!
Note that the InputStream returned by the Resource implementation
needs to be a fresh one on each call, as JavaMail will invoke getInputStream()
multiple times.
NOTE: Invoke addInline
after setText
; else, mail readers might not be able to resolve inline references correctly.
Params: - contentId – the content ID to use. Will end up as "Content-ID" header
in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
Can be referenced in HTML source via src="cid:myId" expressions.
- resource – the resource to take the content from
Throws: - MessagingException – in case of errors
See Also:
/**
* Add an inline element to the MimeMessage, taking the content from a
* {@code org.springframework.core.io.Resource}.
* <p>The content type will be determined by the name of the given
* content file. Do not use this for temporary files with arbitrary
* filenames (possibly ending in ".tmp" or the like)!
* <p>Note that the InputStream returned by the Resource implementation
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
* {@code getInputStream()} multiple times.
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@link #setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param contentId the content ID to use. Will end up as "Content-ID" header
* in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
* Can be referenced in HTML source via src="cid:myId" expressions.
* @param resource the resource to take the content from
* @throws MessagingException in case of errors
* @see #setText
* @see #addInline(String, java.io.File)
* @see #addInline(String, javax.activation.DataSource)
*/
public void addInline(String contentId, Resource resource) throws MessagingException {
Assert.notNull(resource, "Resource must not be null");
String contentType = getFileTypeMap().getContentType(resource.getFilename());
addInline(contentId, resource, contentType);
}
Add an inline element to the MimeMessage, taking the content from an org.springframework.core.InputStreamResource
, and specifying the content type explicitly. You can determine the content type for any given filename via a Java
Activation Framework's FileTypeMap, for example the one held by this helper.
Note that the InputStream returned by the InputStreamSource implementation
needs to be a fresh one on each call, as JavaMail will invoke getInputStream()
multiple times.
NOTE: Invoke addInline
after setText
; else, mail readers might not be able to resolve inline references correctly.
Params: - contentId – the content ID to use. Will end up as "Content-ID" header
in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
Can be referenced in HTML source via src="cid:myId" expressions.
- inputStreamSource – the resource to take the content from
- contentType – the content type to use for the element
Throws: - MessagingException – in case of errors
See Also:
/**
* Add an inline element to the MimeMessage, taking the content from an
* {@code org.springframework.core.InputStreamResource}, and
* specifying the content type explicitly.
* <p>You can determine the content type for any given filename via a Java
* Activation Framework's FileTypeMap, for example the one held by this helper.
* <p>Note that the InputStream returned by the InputStreamSource implementation
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
* {@code getInputStream()} multiple times.
* <p><b>NOTE:</b> Invoke {@code addInline} <i>after</i> {@code setText};
* else, mail readers might not be able to resolve inline references correctly.
* @param contentId the content ID to use. Will end up as "Content-ID" header
* in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>".
* Can be referenced in HTML source via src="cid:myId" expressions.
* @param inputStreamSource the resource to take the content from
* @param contentType the content type to use for the element
* @throws MessagingException in case of errors
* @see #setText
* @see #getFileTypeMap
* @see #addInline(String, org.springframework.core.io.Resource)
* @see #addInline(String, javax.activation.DataSource)
*/
public void addInline(String contentId, InputStreamSource inputStreamSource, String contentType)
throws MessagingException {
Assert.notNull(inputStreamSource, "InputStreamSource must not be null");
if (inputStreamSource instanceof Resource && ((Resource) inputStreamSource).isOpen()) {
throw new IllegalArgumentException(
"Passed-in Resource contains an open stream: invalid argument. " +
"JavaMail requires an InputStreamSource that creates a fresh stream for every call.");
}
DataSource dataSource = createDataSource(inputStreamSource, contentType, "inline");
addInline(contentId, dataSource);
}
Add an attachment to the MimeMessage, taking the content from a javax.activation.DataSource
. Note that the InputStream returned by the DataSource implementation
needs to be a fresh one on each call, as JavaMail will invoke getInputStream()
multiple times.
Params: - attachmentFilename – the name of the attachment as it will
appear in the mail (the content type will be determined by this)
- dataSource – the
javax.activation.DataSource
to take the content from, determining the InputStream and the content type
Throws: - MessagingException – in case of errors
See Also:
/**
* Add an attachment to the MimeMessage, taking the content from a
* {@code javax.activation.DataSource}.
* <p>Note that the InputStream returned by the DataSource implementation
* needs to be a <i>fresh one on each call</i>, as JavaMail will invoke
* {@code getInputStream()} multiple times.
* @param attachmentFilename the name of the attachment as it will
* appear in the mail (the content type will be determined by this)
* @param dataSource the {@code javax.activation.DataSource} to take
* the content from, determining the InputStream and the content type
* @throws MessagingException in case of errors
* @see #addAttachment(String, org.springframework.core.io.InputStreamSource)
* @see #addAttachment(String, java.io.File)
*/
public void addAttachment(String attachmentFilename, DataSource dataSource) throws MessagingException {
Assert.notNull(attachmentFilename, "Attachment filename must not be null");
Assert.notNull(dataSource, "DataSource must not be null");
try {
MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setDisposition(MimeBodyPart.ATTACHMENT);
mimeBodyPart.setFileName(MimeUtility.encodeText(attachmentFilename));
mimeBodyPart.setDataHandler(new DataHandler(dataSource));
getRootMimeMultipart().addBodyPart(mimeBodyPart);
}
catch (UnsupportedEncodingException ex) {
throw new MessagingException("Failed to encode attachment filename", ex);
}
}
Add an attachment to the MimeMessage, taking the content from a java.io.File
. The content type will be determined by the name of the given
content file. Do not use this for temporary files with arbitrary
filenames (possibly ending in ".tmp" or the like)!
Params: - attachmentFilename – the name of the attachment as it will
appear in the mail
- file – the File resource to take the content from
Throws: - MessagingException – in case of errors
See Also:
/**
* Add an attachment to the MimeMessage, taking the content from a
* {@code java.io.File}.
* <p>The content type will be determined by the name of the given
* content file. Do not use this for temporary files with arbitrary
* filenames (possibly ending in ".tmp" or the like)!
* @param attachmentFilename the name of the attachment as it will
* appear in the mail
* @param file the File resource to take the content from
* @throws MessagingException in case of errors
* @see #addAttachment(String, org.springframework.core.io.InputStreamSource)
* @see #addAttachment(String, javax.activation.DataSource)
*/
public void addAttachment(String attachmentFilename, File file) throws MessagingException {
Assert.notNull(file, "File must not be null");
FileDataSource dataSource = new FileDataSource(file);
dataSource.setFileTypeMap(getFileTypeMap());
addAttachment(attachmentFilename, dataSource);
}
Add an attachment to the MimeMessage, taking the content from an org.springframework.core.io.InputStreamResource
. The content type will be determined by the given filename for
the attachment. Thus, any content source will be fine, including
temporary files with arbitrary filenames.
Note that the InputStream returned by the InputStreamSource
implementation needs to be a fresh one on each call, as JavaMail will invoke getInputStream()
multiple times.
Params: - attachmentFilename – the name of the attachment as it will
appear in the mail
- inputStreamSource – the resource to take the content from
(all of Spring's Resource implementations can be passed in here)
Throws: - MessagingException – in case of errors
See Also:
/**
* Add an attachment to the MimeMessage, taking the content from an
* {@code org.springframework.core.io.InputStreamResource}.
* <p>The content type will be determined by the given filename for
* the attachment. Thus, any content source will be fine, including
* temporary files with arbitrary filenames.
* <p>Note that the InputStream returned by the InputStreamSource
* implementation needs to be a <i>fresh one on each call</i>, as
* JavaMail will invoke {@code getInputStream()} multiple times.
* @param attachmentFilename the name of the attachment as it will
* appear in the mail
* @param inputStreamSource the resource to take the content from
* (all of Spring's Resource implementations can be passed in here)
* @throws MessagingException in case of errors
* @see #addAttachment(String, java.io.File)
* @see #addAttachment(String, javax.activation.DataSource)
* @see org.springframework.core.io.Resource
*/
public void addAttachment(String attachmentFilename, InputStreamSource inputStreamSource)
throws MessagingException {
String contentType = getFileTypeMap().getContentType(attachmentFilename);
addAttachment(attachmentFilename, inputStreamSource, contentType);
}
Add an attachment to the MimeMessage, taking the content from an org.springframework.core.io.InputStreamResource
. Note that the InputStream returned by the InputStreamSource
implementation needs to be a fresh one on each call, as JavaMail will invoke getInputStream()
multiple times.
Params: - attachmentFilename – the name of the attachment as it will
appear in the mail
- inputStreamSource – the resource to take the content from
(all of Spring's Resource implementations can be passed in here)
- contentType – the content type to use for the element
Throws: - MessagingException – in case of errors
See Also:
/**
* Add an attachment to the MimeMessage, taking the content from an
* {@code org.springframework.core.io.InputStreamResource}.
* <p>Note that the InputStream returned by the InputStreamSource
* implementation needs to be a <i>fresh one on each call</i>, as
* JavaMail will invoke {@code getInputStream()} multiple times.
* @param attachmentFilename the name of the attachment as it will
* appear in the mail
* @param inputStreamSource the resource to take the content from
* (all of Spring's Resource implementations can be passed in here)
* @param contentType the content type to use for the element
* @throws MessagingException in case of errors
* @see #addAttachment(String, java.io.File)
* @see #addAttachment(String, javax.activation.DataSource)
* @see org.springframework.core.io.Resource
*/
public void addAttachment(
String attachmentFilename, InputStreamSource inputStreamSource, String contentType)
throws MessagingException {
Assert.notNull(inputStreamSource, "InputStreamSource must not be null");
if (inputStreamSource instanceof Resource && ((Resource) inputStreamSource).isOpen()) {
throw new IllegalArgumentException(
"Passed-in Resource contains an open stream: invalid argument. " +
"JavaMail requires an InputStreamSource that creates a fresh stream for every call.");
}
DataSource dataSource = createDataSource(inputStreamSource, contentType, attachmentFilename);
addAttachment(attachmentFilename, dataSource);
}
Create an Activation Framework DataSource for the given InputStreamSource.
Params: - inputStreamSource – the InputStreamSource (typically a Spring Resource)
- contentType – the content type
- name – the name of the DataSource
Returns: the Activation Framework DataSource
/**
* Create an Activation Framework DataSource for the given InputStreamSource.
* @param inputStreamSource the InputStreamSource (typically a Spring Resource)
* @param contentType the content type
* @param name the name of the DataSource
* @return the Activation Framework DataSource
*/
protected DataSource createDataSource(
final InputStreamSource inputStreamSource, final String contentType, final String name) {
return new DataSource() {
@Override
public InputStream getInputStream() throws IOException {
return inputStreamSource.getInputStream();
}
@Override
public OutputStream getOutputStream() {
throw new UnsupportedOperationException("Read-only javax.activation.DataSource");
}
@Override
public String getContentType() {
return contentType;
}
@Override
public String getName() {
return name;
}
};
}
}