| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 |
| * |
| * https://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.apache.commons.mail; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.UnsupportedEncodingException; |
| import java.net.URL; |
| import java.nio.file.Files; |
| import java.nio.file.OpenOption; |
| import java.nio.file.Path; |
| import java.util.Objects; |
| |
| import javax.activation.DataHandler; |
| import javax.activation.DataSource; |
| import javax.activation.FileDataSource; |
| import javax.activation.FileTypeMap; |
| import javax.activation.URLDataSource; |
| import javax.mail.BodyPart; |
| import javax.mail.MessagingException; |
| import javax.mail.internet.MimeBodyPart; |
| import javax.mail.internet.MimeMultipart; |
| import javax.mail.internet.MimePart; |
| import javax.mail.internet.MimeUtility; |
| |
| import org.apache.commons.mail.activation.PathDataSource; |
| |
| /** |
| * A multipart email. |
| * <p> |
| * This class is used to send multi-part internet email like messages with attachments. |
| * </p> |
| * <p> |
| * To create a multi-part email, call the default constructor and then you can call setMsg() to set the message and call the different attach() methods. |
| * </p> |
| * |
| * @since 1.0 |
| */ |
| public class MultiPartEmail extends Email { |
| |
| /** Body portion of the email. */ |
| private MimeMultipart container; |
| |
| /** The message container. */ |
| private BodyPart primaryBodyPart; |
| |
| /** The MIME subtype. */ |
| private String subType; |
| |
| /** Indicates if the message has been initialized. */ |
| private boolean initialized; |
| |
| /** Indicates if attachments have been added to the message. */ |
| private boolean hasAttachments; |
| |
| /** |
| * Constructs a new instance. |
| */ |
| public MultiPartEmail() { |
| // empty |
| } |
| |
| /** |
| * Adds a new part to the email. |
| * |
| * @param multipart The MimeMultipart. |
| * @return An Email. |
| * @throws EmailException see javax.mail.internet.MimeBodyPart for definitions |
| * @since 1.0 |
| */ |
| public Email addPart(final MimeMultipart multipart) throws EmailException { |
| try { |
| return addPart(multipart, getContainer().getCount()); |
| } catch (final MessagingException e) { |
| throw new EmailException(e); |
| } |
| } |
| |
| /** |
| * Adds a new part to the email. |
| * |
| * @param multipart The part to add. |
| * @param index The index to add at. |
| * @return The email. |
| * @throws EmailException An error occurred while adding the part. |
| * @since 1.0 |
| */ |
| public Email addPart(final MimeMultipart multipart, final int index) throws EmailException { |
| final BodyPart bodyPart = createBodyPart(); |
| try { |
| bodyPart.setContent(multipart); |
| getContainer().addBodyPart(bodyPart, index); |
| } catch (final MessagingException e) { |
| throw new EmailException(e); |
| } |
| |
| return this; |
| } |
| |
| /** |
| * Adds a new part to the email. |
| * |
| * @param partContent The content. |
| * @param partContentType The content type. |
| * @return An Email. |
| * @throws EmailException see javax.mail.internet.MimeBodyPart for definitions |
| * @since 1.0 |
| */ |
| public Email addPart(final String partContent, final String partContentType) throws EmailException { |
| final BodyPart bodyPart = createBodyPart(); |
| try { |
| bodyPart.setContent(partContent, partContentType); |
| getContainer().addBodyPart(bodyPart); |
| } catch (final MessagingException e) { |
| throw new EmailException(e); |
| } |
| |
| return this; |
| } |
| |
| /** |
| * Attaches a file specified as a DataSource interface. |
| * |
| * @param dataSource A DataSource interface for the file. |
| * @param name The name field for the attachment. |
| * @param description A description for the attachment. |
| * @return A MultiPartEmail. |
| * @throws EmailException see javax.mail.internet.MimeBodyPart for definitions |
| * @since 1.0 |
| */ |
| public MultiPartEmail attach(final DataSource dataSource, final String name, final String description) throws EmailException { |
| EmailException.checkNonNull(dataSource, () -> "Invalid Datasource."); |
| // verify that the DataSource is valid |
| try (InputStream inputStream = dataSource.getInputStream()) { |
| EmailException.checkNonNull(inputStream, () -> "Invalid Datasource."); |
| } catch (final IOException e) { |
| throw new EmailException("Invalid Datasource.", e); |
| } |
| return attach(dataSource, name, description, EmailAttachment.ATTACHMENT); |
| } |
| |
| /** |
| * Attaches a file specified as a DataSource interface. |
| * |
| * @param dataSource A DataSource interface for the file. |
| * @param name The name field for the attachment. |
| * @param description A description for the attachment. |
| * @param disposition Either mixed or inline. |
| * @return A MultiPartEmail. |
| * @throws EmailException see javax.mail.internet.MimeBodyPart for definitions |
| * @since 1.0 |
| */ |
| public MultiPartEmail attach(final DataSource dataSource, String name, final String description, final String disposition) throws EmailException { |
| if (EmailUtils.isEmpty(name)) { |
| name = dataSource.getName(); |
| } |
| try { |
| final BodyPart bodyPart = createBodyPart(); |
| bodyPart.setDisposition(disposition); |
| bodyPart.setFileName(MimeUtility.encodeText(name)); |
| bodyPart.setDescription(description); |
| bodyPart.setDataHandler(new DataHandler(dataSource)); |
| getContainer().addBodyPart(bodyPart); |
| } catch (final UnsupportedEncodingException | MessagingException e) { |
| // in case the file name could not be encoded |
| throw new EmailException(e); |
| } |
| setBoolHasAttachments(true); |
| return this; |
| } |
| |
| /** |
| * Attaches an EmailAttachment. |
| * |
| * @param attachment An EmailAttachment. |
| * @return A MultiPartEmail. |
| * @throws EmailException see javax.mail.internet.MimeBodyPart for definitions |
| * @since 1.0 |
| */ |
| public MultiPartEmail attach(final EmailAttachment attachment) throws EmailException { |
| EmailException.checkNonNull(attachment, () -> "Invalid attachment."); |
| MultiPartEmail result = null; |
| final URL url = attachment.getURL(); |
| if (url == null) { |
| String fileName = null; |
| try { |
| fileName = attachment.getPath(); |
| final File file = new File(fileName); |
| if (!file.exists()) { |
| throw new IOException("\"" + fileName + "\" does not exist"); |
| } |
| result = attach(new FileDataSource(file), attachment.getName(), attachment.getDescription(), attachment.getDisposition()); |
| } catch (final IOException e) { |
| throw new EmailException("Cannot attach file \"" + fileName + "\"", e); |
| } |
| } else { |
| result = attach(url, attachment.getName(), attachment.getDescription(), attachment.getDisposition()); |
| } |
| return result; |
| } |
| |
| /** |
| * Attaches a file. |
| * |
| * @param file A file attachment |
| * @return A MultiPartEmail. |
| * @throws EmailException see javax.mail.internet.MimeBodyPart for definitions |
| * @since 1.3 |
| */ |
| public MultiPartEmail attach(final File file) throws EmailException { |
| final String fileName = file.getAbsolutePath(); |
| try { |
| if (!file.exists()) { |
| throw new IOException("\"" + fileName + "\" does not exist"); |
| } |
| return attach(new FileDataSource(file), file.getName(), null, EmailAttachment.ATTACHMENT); |
| } catch (final IOException e) { |
| throw new EmailException("Cannot attach file \"" + fileName + "\"", e); |
| } |
| } |
| |
| /** |
| * Attaches a path. |
| * |
| * @param file A file attachment. |
| * @param options options for opening file streams. |
| * @return A MultiPartEmail. |
| * @throws EmailException see javax.mail.internet.MimeBodyPart for definitions |
| * @since 1.6.0 |
| */ |
| public MultiPartEmail attach(final Path file, final OpenOption... options) throws EmailException { |
| final Path fileName = file.toAbsolutePath(); |
| try { |
| if (!Files.exists(file)) { |
| throw new IOException("\"" + fileName + "\" does not exist"); |
| } |
| return attach(new PathDataSource(file, FileTypeMap.getDefaultFileTypeMap(), options), Objects.toString(file.getFileName(), null), null, |
| EmailAttachment.ATTACHMENT); |
| } catch (final IOException e) { |
| throw new EmailException("Cannot attach file \"" + fileName + "\"", e); |
| } |
| } |
| |
| /** |
| * Attaches a file located by its URL. The disposition of the file is set to mixed. |
| * |
| * @param url The URL of the file (may be any valid URL). |
| * @param name The name field for the attachment. |
| * @param description A description for the attachment. |
| * @return A MultiPartEmail. |
| * @throws EmailException see javax.mail.internet.MimeBodyPart for definitions |
| * @since 1.0 |
| */ |
| public MultiPartEmail attach(final URL url, final String name, final String description) throws EmailException { |
| return attach(url, name, description, EmailAttachment.ATTACHMENT); |
| } |
| |
| /** |
| * Attaches a file located by its URL. |
| * |
| * @param url The URL of the file (may be any valid URL). |
| * @param name The name field for the attachment. |
| * @param description A description for the attachment. |
| * @param disposition Either mixed or inline. |
| * @return A MultiPartEmail. |
| * @throws EmailException see javax.mail.internet.MimeBodyPart for definitions |
| * @since 1.0 |
| */ |
| public MultiPartEmail attach(final URL url, final String name, final String description, final String disposition) throws EmailException { |
| // verify that the URL is valid |
| try { |
| url.openStream().close(); |
| } catch (final IOException e) { |
| throw new EmailException("Invalid URL set:" + url, e); |
| } |
| return attach(new URLDataSource(url), name, description, disposition); |
| } |
| |
| /** |
| * Builds the MimeMessage. Please note that a user rarely calls this method directly and only if he/she is interested in the sending the underlying |
| * MimeMessage without commons-email. |
| * |
| * @throws EmailException if there was an error. |
| * @since 1.0 |
| */ |
| @Override |
| public void buildMimeMessage() throws EmailException { |
| try { |
| if (primaryBodyPart != null) { |
| // before a multipart message can be sent, we must make sure that |
| // the content for the main body part was actually set. If not, |
| // an IOException will be thrown during super.send(). |
| |
| final BodyPart body = getPrimaryBodyPart(); |
| try { |
| body.getContent(); |
| } catch (final IOException e) // NOPMD |
| { |
| // do nothing here. |
| // content will be set to an empty string as a result. |
| // (Should this really be rethrown as an email exception?) |
| // throw new EmailException(e); |
| } |
| } |
| |
| if (subType != null) { |
| getContainer().setSubType(subType); |
| } |
| |
| super.buildMimeMessage(); |
| } catch (final MessagingException e) { |
| throw new EmailException(e); |
| } |
| } |
| |
| /** |
| * Creates a body part object. Can be overridden if you don't want to create a BodyPart. |
| * |
| * @return the created body part |
| */ |
| protected BodyPart createBodyPart() { |
| return new MimeBodyPart(); |
| } |
| |
| /** |
| * Creates a mime multipart object. |
| * |
| * @return the created mime part |
| */ |
| protected MimeMultipart createMimeMultipart() { |
| return new MimeMultipart(); |
| } |
| |
| /** |
| * Gets the message container. |
| * |
| * @return The message container. |
| * @since 1.0 |
| */ |
| protected MimeMultipart getContainer() { |
| if (!initialized) { |
| init(); |
| } |
| return container; |
| } |
| |
| /** |
| * Gets first body part of the message. |
| * |
| * @return The primary body part. |
| * @throws MessagingException An error occurred while getting the primary body part. |
| * @since 1.0 |
| */ |
| protected BodyPart getPrimaryBodyPart() throws MessagingException { |
| if (!initialized) { |
| init(); |
| } |
| // Add the first body part to the message. The fist body part must be |
| if (primaryBodyPart == null) { |
| primaryBodyPart = createBodyPart(); |
| getContainer().addBodyPart(primaryBodyPart, 0); |
| } |
| return primaryBodyPart; |
| } |
| |
| /** |
| * Gets the MIME subtype of the email. |
| * |
| * @return MIME subtype of the email |
| * @since 1.0 |
| */ |
| public String getSubType() { |
| return subType; |
| } |
| |
| /** |
| * Initialize the multipart email. |
| * |
| * @since 1.0 |
| */ |
| protected void init() { |
| if (initialized) { |
| throw new IllegalStateException("Already initialized"); |
| } |
| container = createMimeMultipart(); |
| super.setContent(container); |
| initialized = true; |
| } |
| |
| /** |
| * Tests whether there are attachments. |
| * |
| * @return true if there are attachments |
| * @since 1.0 |
| */ |
| public boolean isBoolHasAttachments() { |
| return hasAttachments; |
| } |
| |
| /** |
| * Tests if this object is initialized. |
| * |
| * @return true if initialized |
| */ |
| protected boolean isInitialized() { |
| return initialized; |
| } |
| |
| /** |
| * Sets whether there are attachments. |
| * |
| * @param hasAttachments the attachments flag |
| * @since 1.0 |
| */ |
| public void setBoolHasAttachments(final boolean hasAttachments) { |
| this.hasAttachments = hasAttachments; |
| } |
| |
| /** |
| * Sets the initialized status of this object. |
| * |
| * @param initialized the initialized status flag |
| */ |
| protected void setInitialized(final boolean initialized) { |
| this.initialized = initialized; |
| } |
| |
| /** |
| * Sets the message of the email. |
| * |
| * @param msg A String. |
| * @return An Email. |
| * @throws EmailException see javax.mail.internet.MimeBodyPart for definitions |
| * @since 1.0 |
| */ |
| @Override |
| public Email setMsg(final String msg) throws EmailException { |
| EmailException.checkNonEmpty(msg, () -> "Invalid message."); |
| try { |
| final BodyPart primary = getPrimaryBodyPart(); |
| if (primary instanceof MimePart && EmailUtils.isNotEmpty(getCharsetName())) { |
| ((MimePart) primary).setText(msg, getCharsetName()); |
| } else { |
| primary.setText(msg); |
| } |
| } catch (final MessagingException e) { |
| throw new EmailException(e); |
| } |
| return this; |
| } |
| |
| /** |
| * Sets the MIME subtype of the email. |
| * |
| * @param subType MIME subtype of the email |
| * @since 1.0 |
| */ |
| public void setSubType(final String subType) { |
| this.subType = subType; |
| } |
| |
| } |