Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
// Copyright (c) 2003-present, Jodd Team (http://jodd.org)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
package jodd.mail;
import jakarta.mail.Address;
import jakarta.mail.Flags;
import jakarta.mail.Message;
import jakarta.mail.MessagingException;
import jakarta.mail.Multipart;
import jakarta.mail.Part;
import jakarta.mail.internet.MimeMessage;
import jakarta.mail.internet.MimePart;
import jakarta.mail.util.ByteArrayDataSource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static jakarta.mail.Flags.*;
/**
* Received email.
*/
public class ReceivedEmail extends CommonEmail {
public static final ReceivedEmail[] EMPTY_ARRAY = new ReceivedEmail[0];
private File attachmentStorage;
/**
* Static constructor for fluent interface.
*
* @return new {@link ReceivedEmail}.
*/
public static ReceivedEmail create() {
return new ReceivedEmail();
}
@Override
public ReceivedEmail clone() {
return create()
//original message
.originalMessage(originalMessage())
// flags
.flags(flags())
// message number and id
.messageNumber(messageNumber())
.messageId(messageId())
// from / reply-to
.from(from())
.replyTo(replyTo())
// recipients
.to(to())
.cc(cc())
// subject
.subject(subject(), subjectEncoding())
// dates
.receivedDate(receivedDate())
.sentDate(sentDate())
// headers - includes priority
.headers(headers())
// content / attachments
.message(messages())
.storeAttachments(attachments())
.attachedMessages(attachedMessages());
}
/**
* Creates an empty {@link ReceivedEmail}.
*/
private ReceivedEmail() {
}
/**
* Creates a {@link ReceivedEmail} from a given {@link Message}.
*
* @param msg {@link Message}
* @param envelope flag if this is an envelope
*/
public ReceivedEmail(final Message msg, final boolean envelope, final File attachmentStorage) {
this.attachmentStorage = attachmentStorage;
this.originalMessage = msg;
try {
parseMessage(msg, envelope);
} catch (final Exception ex) {
throw new MailException("Message parsing failed", ex);
}
}
/**
* Parses {@link Message} and extracts all data for the received message.
*
* @param msg {@link Message} to parse.
* @throws IOException if there is an error with the content
* @throws MessagingException if there is an error.
*/
protected void parseMessage(final Message msg, final boolean envelope) throws MessagingException, IOException {
// flags
flags(msg.getFlags());
// message number
messageNumber(msg.getMessageNumber());
if (msg instanceof MimeMessage) {
messageId(((MimeMessage) msg).getMessageID());
}
// single from
final Address[] addresses = msg.getFrom();
if (addresses != null && addresses.length > 0) {
from(addresses[0]);
}
// reply-to
replyTo(msg.getReplyTo());
// recipients
to(msg.getRecipients(Message.RecipientType.TO));
cc(msg.getRecipients(Message.RecipientType.CC));
// no BCC because this will always be empty
// subject
subject(msg.getSubject());
// dates
receivedDate(msg.getReceivedDate());
sentDate(msg.getSentDate());
// headers
headers(msg.getAllHeaders());
// content
if (!envelope) {
processPart(msg);
}
}
/**
* Process part of the received message. All parts are simply added to the {@link ReceivedEmail},
* i.e. hierarchy is not saved.
*
* @param part {@link Part} of received message
* @throws IOException if there is an error with the content.
* @throws MessagingException if there is an error.
*/
protected void processPart(final Part part) throws MessagingException, IOException {
final Object content = part.getContent();
if (content instanceof String) {
addStringContent(part, (String) content);
} else if (content instanceof Multipart) {
processMultipart((Multipart) content);
} else if (content instanceof InputStream) {
addAttachment(part, (InputStream) content, attachmentStorage);
} else if (content instanceof MimeMessage) {
final MimeMessage mimeMessage = (MimeMessage) content;
attachedMessage(new ReceivedEmail(mimeMessage, false, attachmentStorage));
} else {
addAttachment(part, part.getInputStream(), attachmentStorage);
}
}
/**
* Process the {@link Multipart}.
*
* @param mp {@link Multipart}
* @throws MessagingException if there is a failure.
* @throws IOException if there is an issue with the {@link Multipart}.
*/
private void processMultipart(final Multipart mp) throws MessagingException, IOException {
final int count = mp.getCount();
for (int i = 0; i < count; i++) {
final Part innerPart = mp.getBodyPart(i);
processPart(innerPart);
}
}
/**
* Adds String content as either {@link EmailAttachment} or as {@link EmailMessage}.
*
* @param part {@link Part}
* @param content Content as {@link String}
* @throws MessagingException if there is a failure.
* @throws UnsupportedEncodingException if the named charset is not supported.
* @see #message(String, String, String)
*/
private void addStringContent(final Part part, final String content) throws MessagingException, UnsupportedEncodingException {
final String contentType = part.getContentType();
final String encoding = EmailUtil.extractEncoding(contentType, StandardCharsets.US_ASCII.name());
final String disposition = part.getDisposition();
if (disposition != null && disposition.equalsIgnoreCase(Part.ATTACHMENT)) {
addAttachment(part, content.getBytes(encoding));
} else {
final String mimeType = EmailUtil.extractMimeType(contentType);
message(content, mimeType, encoding);
}
}
/**
* Returns the Content-ID of this {@link Part}. Returns {@code null} if none present.
*
* @param part {@link Part} the Part to parse.
* @return String containing content ID.
* @throws MessagingException if there is a failure.
* @see MimePart#getContentID()
*/
protected static String parseContentId(final Part part) throws MessagingException {
if (part instanceof MimePart) {
final MimePart mp = (MimePart) part;
return mp.getContentID();
} else {
return null;
}
}
/**
* Returns {@code true} if the {@link Part} is inline.
*
* @param part {@link Part} to parse.
* @return {@code true} if the {@link Part} is inline.
* @throws MessagingException if there is a failure.
*/
protected static boolean parseInline(final Part part) throws MessagingException {
if (part instanceof MimePart) {
final String dispositionId = part.getDisposition();
return dispositionId != null && dispositionId.equalsIgnoreCase("inline");
}
return false;
}
// ---------------------------------------------------------------- original message
/**
* {@link Message} for this {@link ReceivedEmail}.
*/
private Message originalMessage;
/**
* @return {@link Message}
*/
public Message originalMessage() {
return originalMessage;
}
/**
* Sets the original message.
*
* @param originalMessage {@link Message} to set.
*/
public ReceivedEmail originalMessage(final Message originalMessage) {
this.originalMessage = originalMessage;
return this;
}
// ---------------------------------------------------------------- flags
/**
* {@link Flags} for this {@link ReceivedEmail}.
*/
private Flags flags;
/**
* @return {@link Flags}
*/
public Flags flags() {
return flags;
}
/**
* Sets the flags.
*
* @param flags {@link Flags} to set.
*/
public ReceivedEmail flags(final Flags flags) {
this.flags = flags;
return this;
}
/**
* Returns {@code true} if message is answered.
*
* @return {@code true} if message is answered.
*/
public boolean isAnswered() {
return flags.contains(Flag.ANSWERED);
}
/**
* Returns {@code true} if message is deleted.
*
* @return {@code true} if message is deleted.
*/
public boolean isDeleted() {
return flags.contains(Flag.DELETED);
}
/**
* Returns {@code true} if message is draft.
*/
public boolean isDraft() {
return flags.contains(Flag.DRAFT);
}
/**
* Returns {@code true} is message is flagged.
*
* @return {@code true} is message is flagged.
*/
public boolean isFlagged() {
return flags.contains(Flag.FLAGGED);
}
/**
* Returns {@code true} if message is recent.
*
* @return {@code true} if message is recent.
*/
public boolean isRecent() {
return flags.contains(Flag.RECENT);
}
/**
* Returns {@code true} if message is seen.
*
* @return {@code true} if message is seen.
*/
public boolean isSeen() {
return flags.contains(Flag.SEEN);
}
// ---------------------------------------------------------------- additional properties
private int messageNumber;
private String messageId;
/**
* Returns message number.
*
* @return message number
*/
public int messageNumber() {
return messageNumber;
}
/**
* Returns message ID if set by server.
*/
public String messageId() {
return messageId;
}
/**
* Sets message number.
*
* @param messageNumber The message number to set.
* @return this
*/
public ReceivedEmail messageNumber(final int messageNumber) {
this.messageNumber = messageNumber;
return this;
}
/**
* Sets message ID.
*/
public ReceivedEmail messageId(final String messageId) {
this.messageId = messageId;
return this;
}
private Date receivedDate;
/**
* Sets email's received {@link Date}.
*
* @param date The received {@link Date} to set.
* @return this
*/
public ReceivedEmail receivedDate(final Date date) {
receivedDate = date;
return this;
}
/**
* Returns email's received {@link Date}.
*
* @return The email's received {@link Date}.
*/
public Date receivedDate() {
return receivedDate;
}
// ---------------------------------------------------------------- attachments
/**
* Adds received attachment.
*
* @param part {@link Part}.
* @param content Content as {@link InputStream}.
* @return this
* @see #attachment(EmailAttachment)
*/
private ReceivedEmail addAttachment(final Part part, final InputStream content, final File attachmentStorage) throws MessagingException, IOException {
final EmailAttachmentBuilder builder = addAttachmentInfo(part);
builder.content(content, part.getContentType());
if (attachmentStorage != null) {
String name = messageId + "-" + (this.attachments().size() + 1);
return storeAttachment(builder.buildFileDataSource(name, attachmentStorage));
}
return storeAttachment(builder.buildByteArrayDataSource());
}
/**
* Adds received attachment.
*
* @param part {@link Part}.
* @param content Content as byte array.
* @return this
* @see #attachment(EmailAttachment)
*/
private ReceivedEmail addAttachment(final Part part, final byte[] content) throws MessagingException {
final EmailAttachmentBuilder builder = addAttachmentInfo(part);
builder.content(content, part.getContentType());
final EmailAttachment attachment = builder.buildByteArrayDataSource();
attachment.setSize(content.length);
return storeAttachment(attachment);
}
/**
* Creates {@link EmailAttachmentBuilder} from {@link Part} and sets Content ID, inline and name.
*
* @param part {@link Part}.
* @return this
* @see #attachment(EmailAttachment)
*/
private static EmailAttachmentBuilder addAttachmentInfo(final Part part) throws MessagingException {
final String fileName = EmailUtil.resolveFileName(part);
final String contentId = parseContentId(part);
final boolean isInline = parseInline(part);
return new EmailAttachmentBuilder()
.name(fileName)
.contentId(contentId)
.inline(isInline);
}
// ---------------------------------------------------------------- inner messages
/**
* {@link List} of attached {@link ReceivedEmail}s.
*/
private final List attachedMessages = new ArrayList<>();
/**
* Adds attached {@link ReceivedEmail}s.
*
* @param emails {@link List} of {@link ReceivedEmail}s to attach.
*/
public ReceivedEmail attachedMessages(final List emails) {
attachedMessages.addAll(emails);
return this;
}
/**
* Adds attached {@link ReceivedEmail}.
*
* @param email {@link ReceivedEmail} to attach.
* @return this
*/
public ReceivedEmail attachedMessage(final ReceivedEmail email) {
attachedMessages.add(email);
return this;
}
/**
* Returns the {@link List} of attached messages.
* If no attached message is available, returns an empty {@link List}.
*
* @return {@link List} of {@link ReceivedEmail}s.
*/
public List attachedMessages() {
return attachedMessages;
}
}