com.github.kahlkn.yui.email.Email Maven / Gradle / Ivy
package com.github.kahlkn.yui.email;
import com.github.kahlkn.artoria.exception.UncheckedException;
import com.github.kahlkn.artoria.io.IOUtils;
import com.github.kahlkn.artoria.logging.Logger;
import com.github.kahlkn.artoria.logging.LoggerFactory;
import com.github.kahlkn.artoria.time.DateTime;
import com.github.kahlkn.artoria.util.*;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.util.*;
import static com.github.kahlkn.artoria.util.Const.*;
import static javax.mail.Flags.Flag.SEEN;
import static javax.mail.Message.RecipientType.*;
/**
* Email object.
* @author Kahle
*/
public class Email {
private static final String APPLICATION_ALL = "application/*";
private static final String MESSAGE_RFC822 = "message/rfc822";
private static final String MULTIPART_ALL = "multipart/*";
private static final String X_PRIORITY = "X-Priority";
private static final String STRING_NAME = "name";
private static final String TEXT_ALL = "text/*";
private static Logger log = LoggerFactory.getLogger(Email.class);
private String charset = DEFAULT_CHARSET_NAME;
private List from = new ArrayList();
private List to = new ArrayList();
private List cc = new ArrayList();
private List bcc = new ArrayList();
private Date sentDate;
private String subject;
private String textContent;
private String htmlContent;
private Map files = new HashMap();
private Boolean debug;
private String messageId;
private String priority;
private Integer size;
private Boolean isRead;
private Message message;
private boolean isTextEmail = false;
private boolean hasAttach = false;
public String getCharset() {
return charset;
}
public Email setCharset(String charset) {
this.charset = charset;
return this;
}
public List getFrom() {
return from;
}
public Email addFrom(List from) {
this.from.addAll(from);
return this;
}
public Email addFrom(String... from) {
try {
for (String s : from) {
Address[] parse = InternetAddress.parse(s);
this.from.addAll(Arrays.asList(parse));
}
return this;
}
catch (Exception e) {
throw new UncheckedException(e);
}
}
public Email addFrom(String from, String displayName) {
try {
if (StringUtils.isNotBlank(displayName)) {
String encodeName = MimeUtility.encodeText(displayName);
this.from.add(new InternetAddress(encodeName + " <" + from + ">"));
}
else {
Address[] parse = InternetAddress.parse(from);
this.from.addAll(Arrays.asList(parse));
}
return this;
}
catch (Exception e) {
throw new UncheckedException(e);
}
}
public Email clearFrom() {
this.from.clear();
return this;
}
public List getTo() {
return to;
}
public Email addTo(List to) {
this.to.addAll(to);
return this;
}
public Email addTo(String... to) {
try {
for (String s : to) {
Address[] parse = InternetAddress.parse(s);
this.to.addAll(Arrays.asList(parse));
}
return this;
} catch (AddressException e) {
throw new RuntimeException(e);
}
}
public Email clearTo() {
this.to.clear();
return this;
}
public List getCc() {
return cc;
}
public Email addCc(List cc) {
this.cc.addAll(cc);
return this;
}
public Email addCc(String... cc) {
try {
for (String s : cc) {
Address[] parse = InternetAddress.parse(s);
this.cc.addAll(Arrays.asList(parse));
}
return this;
}
catch (Exception e) {
throw new UncheckedException(e);
}
}
public Email clearCc() {
this.cc.clear();
return this;
}
public List getBcc() {
return bcc;
}
public Email addBcc(List bcc) {
this.bcc.addAll(bcc);
return this;
}
public Email addBcc(String... bcc) {
try {
for (String s : bcc) {
Address[] parse = InternetAddress.parse(s);
this.bcc.addAll(Arrays.asList(parse));
}
return this;
}
catch (Exception e) {
throw new UncheckedException(e);
}
}
public Email clearBcc() {
this.bcc.clear();
return this;
}
public Date getSentDate() {
return sentDate;
}
public Email setSentDate(Date sentDate) {
this.sentDate = sentDate;
return this;
}
public String getSubject() {
return subject;
}
public Email setSubject(String subject) {
this.subject = subject;
return this;
}
public String getTextContent() {
return textContent;
}
public Email setTextContent(String textContent) {
this.textContent = textContent;
return this;
}
public String getHtmlContent() {
return htmlContent;
}
public Email setHtmlContent(String htmlContent) {
this.htmlContent = htmlContent;
return this;
}
public Map getFiles() {
return files;
}
public Email addFiles(List files) {
for (File file : files) {
this.files.put(file.getName(), file);
}
return this;
}
public Email addFiles(File... files) {
this.addFiles(Arrays.asList(files));
return this;
}
public Email addFile(String fName, File file) {
fName = StringUtils.isBlank(fName) ? file.getName() : fName;
this.files.put(fName, file);
return this;
}
public Boolean getDebug() {
return debug;
}
public Email setDebug(Boolean debug) {
this.debug = debug;
return this;
}
public String getMessageId() {
return messageId;
}
public Email setMessageId(String messageId) {
this.messageId = messageId;
return this;
}
public String getPriority() {
return priority;
}
public Email setPriority(String priority) {
this.priority = priority;
return this;
}
public Integer getSize() {
return size;
}
public Email setSize(Integer size) {
this.size = size;
return this;
}
public Boolean getIsRead() {
return isRead;
}
public Email setIsRead(Boolean isRead) {
this.isRead = isRead;
return this;
}
public Message getMessage() {
return message;
}
public Email setMessage(Message message) {
this.message = message;
return this;
}
public boolean getIsTextEmail() {
return isTextEmail;
}
public Email setIsTextEmail(boolean isTextEmail) {
this.isTextEmail = isTextEmail;
return this;
}
public boolean getHasAttach() {
return hasAttach;
}
public Email setHasAttach(boolean hasAttach) {
this.hasAttach = hasAttach;
return this;
}
public Email saveAttach(File path) throws IOException, MessagingException {
if (!path.exists() && !path.mkdirs()) {
throw new IOException("Create directory \"" + path + "\" failure. ");
}
if (hasAttach && MapUtils.isEmpty(this.files)) {
List files = Email.saveAttach(message, path);
if (CollectionUtils.isEmpty(files)) { return this; }
this.addFiles(files);
}
return this;
}
public MimeMessage build(Session session) throws IOException, MessagingException {
Assert.notNull(session, "Parameter \"session\" must not blank. ");
if (debug != null) {
session.setDebug(debug);
}
MimeMessage message = new MimeMessage(session);
Assert.notEmpty(from, "Parameter \"from\" must not blank. ");
Address[] tmp = new Address[from.size()];
from.toArray(tmp);
message.addFrom(tmp);
Assert.notEmpty(to, "Parameter \"to\" must not blank. ");
tmp = new Address[to.size()];
to.toArray(tmp);
message.addRecipients(Message.RecipientType.TO, tmp);
if (CollectionUtils.isNotEmpty(cc)) {
tmp = new Address[cc.size()];
cc.toArray(tmp);
message.addRecipients(Message.RecipientType.CC, tmp);
}
if (CollectionUtils.isNotEmpty(bcc)) {
tmp = new Address[bcc.size()];
bcc.toArray(tmp);
message.addRecipients(Message.RecipientType.BCC, tmp);
}
if (sentDate != null) {
message.setSentDate(sentDate);
}
if (StringUtils.isNotBlank(subject)) {
message.setSubject(subject, charset);
}
if (StringUtils.isNotBlank(htmlContent) || MapUtils.isNotEmpty(files)) {
MimeMultipart mimeMultipart = new MimeMultipart();
if (StringUtils.isNotBlank(htmlContent)) {
String contentType = String.format("text/html; charset=%s", charset.toLowerCase());
MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setContent(htmlContent, contentType);
mimeMultipart.addBodyPart(mimeBodyPart);
}
if (MapUtils.isNotEmpty(files)) {
for (Map.Entry entry : files.entrySet()) {
MimeBodyPart filePart = new MimeBodyPart();
filePart.setDataHandler(new DataHandler(new FileDataSource(entry.getValue())));
filePart.setFileName(MimeUtility.encodeWord(entry.getKey(), charset, "B"));
mimeMultipart.addBodyPart(filePart);
}
}
message.setContent(mimeMultipart);
}
else if (StringUtils.isNotBlank(textContent)) {
message.setText(textContent, charset);
}
return message;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("MessageId : ").append(messageId).append(ENDL);
String fromStr = from.size() > 2 ? Email.serializeAddress(from.subList(0, 2)) + " ..." : Email.serializeAddress(from);
builder.append("From : ").append(fromStr).append(ENDL);
String toStr = to.size() > 2 ? Email.serializeAddress(to.subList(0, 2)) + " ..." : Email.serializeAddress(to);
builder.append("To : ").append(toStr).append(ENDL);
if (CollectionUtils.isNotEmpty(cc)) {
String ccStr = cc.size() > 2 ? Email.serializeAddress(cc.subList(0, 2)) + " ..." : Email.serializeAddress(cc);
builder.append("Cc : ").append(ccStr).append(ENDL);
}
if (CollectionUtils.isNotEmpty(bcc)) {
String bccStr = bcc.size() > 2 ? Email.serializeAddress(bcc.subList(0, 2)) + " ..." : Email.serializeAddress(bcc);
builder.append("Bcc : ").append(bccStr).append(ENDL);
}
builder.append("SentDate : ").append(DateTime.create(sentDate).toString()).append(ENDL);
builder.append("Priority : ").append(priority).append(ENDL);
builder.append("Size : ").append(size).append(" Byte").append(ENDL);
builder.append("HasAttach : ").append(hasAttach).append(ENDL);
builder.append("IsRead : ").append(isRead).append(ENDL);
builder.append("IsTextEmail : ").append(isTextEmail).append(ENDL);
String subject = this.subject.trim();
subject = subject.length() > 36 ? subject.substring(0, 36) : subject;
builder.append("Subject : ").append(subject).append(ENDL);
String content = isTextEmail ? textContent : htmlContent;
content = content.trim();
content = content.length() > 200 ? content.substring(0, 200) : content;
builder.append("Summary : ").append(content).append(ENDL);
return builder.toString();
}
public static Email parse(Message message) throws IOException, MessagingException {
Email email = new Email();
email.setMessage(message);
if (message instanceof MimeMessage) {
email.setMessageId(((MimeMessage) message).getMessageID());
}
String[] xPrioHeaders = message.getHeader(X_PRIORITY);
email.setPriority(ArrayUtils.isNotEmpty(xPrioHeaders) ? xPrioHeaders[0] : null);
email.setSize(message.getSize());
Flags flags = message.getFlags();
email.setIsRead(flags.contains(SEEN));
email.setSentDate(message.getSentDate());
Address[] from = message.getFrom();
email.addFrom(Arrays.asList(from));
Address[] recipients = message.getRecipients(TO);
email.addTo(Arrays.asList(recipients));
Address[] tmp = message.getRecipients(CC);
if (tmp != null) {
email.addCc(Arrays.asList(tmp));
}
tmp = message.getRecipients(BCC);
if (tmp != null) {
email.addBcc(Arrays.asList(tmp));
}
String subject = message.getSubject();
subject = MimeUtility.decodeText(subject);
email.setSubject(subject);
String contentType = message.getContentType();
boolean contains = contentType.contains(STRING_NAME);
if (message.isMimeType(TEXT_ALL) && !contains) {
email.setIsTextEmail(true);
email.setTextContent(message.getContent().toString());
}
else {
email.setIsTextEmail(false);
email.setHtmlContent(Email.takeContent(message));
}
email.setHasAttach(Email.containAttach(message));
return email;
}
private static String serializeAddress(Address address) {
try {
if (address instanceof InternetAddress) {
InternetAddress addr = (InternetAddress) address;
String nickname = addr.getPersonal();
nickname = StringUtils.isNotBlank(nickname)
? MimeUtility.decodeText(nickname) : EMPTY_STRING;
return nickname + "<" + addr.getAddress() + ">";
}
else {
return address.toString();
}
}
catch (Exception e) {
throw new UncheckedException(e);
}
}
private static String serializeAddress(List addresses) {
StringBuilder builder = new StringBuilder();
for (Address address : addresses) {
String addressStr = Email.serializeAddress(address);
builder.append(addressStr).append(", ");
}
builder.deleteCharAt(builder.length() - 2);
return builder.toString();
}
private static String takeContent(Part part) throws IOException, MessagingException {
StringBuilder builder = new StringBuilder();
boolean containAttach = part.getContentType().contains(STRING_NAME);
if (part.isMimeType(TEXT_ALL) && !containAttach) {
builder.append(part.getContent().toString());
}
else if (part.isMimeType(MESSAGE_RFC822)) {
builder.append(Email.takeContent((Part) part.getContent()));
}
else if (part.isMimeType(MULTIPART_ALL)) {
Multipart multipart = (Multipart) part.getContent();
int partCount = multipart.getCount();
for (int i = 0; i < partCount; i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
builder.append(Email.takeContent(bodyPart));
}
}
return builder.toString();
}
private static boolean containAttach(Part part) throws IOException, MessagingException {
boolean hasAttach = false;
if (part.isMimeType(MULTIPART_ALL)) {
// Handle multipart
MimeMultipart multipart = (MimeMultipart) part.getContent();
int partCount = multipart.getCount();
for (int i = 0; i < partCount; i++) {
BodyPart bPart = multipart.getBodyPart(i);
String disp = bPart.getDisposition();
boolean isAttach = disp != null, isInline = isAttach;
isAttach = isAttach && disp.equalsIgnoreCase(Part.ATTACHMENT);
isInline = isInline && disp.equalsIgnoreCase(Part.INLINE);
if (isAttach || isInline ||
bPart.isMimeType(APPLICATION_ALL) ||
bPart.getContentType().contains(STRING_NAME)) {
hasAttach = true;
}
else if (bPart.isMimeType(MULTIPART_ALL)) {
hasAttach = Email.containAttach(bPart);
}
if (hasAttach) { break; }
}
}
else if (part.isMimeType(MESSAGE_RFC822)) {
hasAttach = Email.containAttach((Part) part.getContent());
}
return hasAttach;
}
private static List saveAttach(Part part, File dir) throws IOException, MessagingException {
List files = new ArrayList();
if (part.isMimeType(MULTIPART_ALL)) {
// Handle multipart
Multipart multipart = (Multipart) part.getContent();
int partCount = multipart.getCount();
for (int i = 0; i < partCount; i++) {
BodyPart bPart = multipart.getBodyPart(i);
String disp = bPart.getDisposition();
boolean isAttach = disp != null, isInline = isAttach;
boolean hasName = isAttach, isApplication = isAttach;
isAttach = isAttach && disp.equalsIgnoreCase(Part.ATTACHMENT);
isInline = isInline && disp.equalsIgnoreCase(Part.INLINE);
hasName = hasName && bPart.getContentType().contains(STRING_NAME);
isApplication = isApplication && bPart.isMimeType(APPLICATION_ALL);
if (isAttach || isInline || hasName || isApplication) {
InputStream in = null;
OutputStream out = null;
try {
in = bPart.getInputStream();
String fName = bPart.getFileName();
fName = MimeUtility.decodeText(fName);
File dest = new File(dir, fName);
// Prevent dest file already exist.
String destStr = PathUtils.notExistPath(dest.toString());
dest = new File(destStr);
if (!dest.createNewFile()) {
throw new IOException("Create file \"" + dest + "\" failure. ");
}
files.add(dest);
out = new FileOutputStream(dest);
IOUtils.copyLarge(in, out);
out.flush();
}
finally {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
}
}
else if (bPart.isMimeType(MULTIPART_ALL)) {
files.addAll(Email.saveAttach(bPart, dir));
}
}
}
else if (part.isMimeType(MESSAGE_RFC822)) {
files.addAll(Email.saveAttach((Part) part.getContent(), dir));
}
return files;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy