All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nervousync.utils.MailUtils Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * Licensed to the Nervousync Studio (NSYC) 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
 *
 *      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.nervousync.utils;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.*;

import jakarta.activation.DataHandler;
import jakarta.activation.DataSource;
import jakarta.activation.FileDataSource;
import jakarta.mail.*;
import jakarta.mail.internet.*;
import jakarta.mail.util.ByteArrayDataSource;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute;
import org.bouncycastle.asn1.smime.SMIMECapability;
import org.bouncycastle.asn1.smime.SMIMECapabilityVector;
import org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.SignerInfoGenerator;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationVerifier;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.mail.smime.SMIMEException;
import org.bouncycastle.mail.smime.SMIMESignedGenerator;
import org.bouncycastle.mail.smime.SMIMESignedParser;
import org.bouncycastle.mail.smime.SMIMEUtil;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.eclipse.angus.mail.imap.IMAPFolder;
import org.eclipse.angus.mail.pop3.POP3Folder;
import org.nervousync.enumerations.mail.MailProtocol;
import org.nervousync.exceptions.mail.MailException;
import org.nervousync.mail.MailObject;
import org.nervousync.mail.authenticator.DefaultAuthenticator;
import org.nervousync.mail.config.MailConfig;
import org.nervousync.mail.operator.ReceiveOperator;
import org.nervousync.mail.operator.SendOperator;
import org.nervousync.mail.protocol.impl.IMAPProtocol;
import org.nervousync.mail.protocol.impl.POP3Protocol;
import org.nervousync.mail.protocol.impl.SMTPProtocol;
import org.nervousync.commons.Globals;
import org.nervousync.security.factory.SecureFactory;

/**
 * 

E-Mail Utilities

* * Current utilities implements features: *
    Send/Receive email
*
    Count email in folder
*
    List folder names
*
    Download email attachment files automatically
*
    Verify email signature
*
    Add signature to email
*
*

电子邮件工具集

* * 此工具集实现以下功能: *
    发送接收电子邮件
*
    获取文件夹中的电子邮件数量
*
    列出所有文件夹名称
*
    自动下载电子邮件中包含的附件
*
    验证电子邮件签名
*
    添加电子签名到邮件
*
* * @author Steven Wee [email protected] * @version $Revision: 1.1.5 $ $Date: Jul 31, 2012 20:54:04 $ */ public final class MailUtils { /** *

Private constructor for MailUtils

*

电子邮件工具集的私有构造方法

*/ private MailUtils() { } /** *

Initialize Mail Agent instance by given mail configure information

*

使用给定的电子邮件配置信息生成电子邮件代理实例对象

* * @param mailConfig Mail configure information define * 邮件配置信息定义 * * @return Generated Mail Agent instance * 生成的电子邮件代理实例对象 */ public static Agent mailAgent(final MailConfig mailConfig) { if (mailConfig == null || StringUtils.isEmpty(mailConfig.getUserName()) || StringUtils.isEmpty(mailConfig.getPassword())) { return null; } return new Agent(mailConfig); } /** *

E-Mail Agent

*

电子邮件代理

* * @author Steven Wee [email protected] * @version $Revision: 1.0.0 $ $Date: Jul 31, 2012 21:03:46 $ */ public static final class Agent { /** * Logger instance * 日志实例 */ private final LoggerUtils.Logger logger = LoggerUtils.getLogger(this.getClass()); /** * Mail account username * 邮件账户用户名 */ private final String userName; /** * Mail account password * 邮件账户密码 */ private final String passWord; /** * Mail send server config * 邮件发送服务器配置信息 */ private final MailConfig.ServerConfig sendConfig; /** * e-mail send operator * 电子邮件发送器 */ private final SendOperator sendOperator; /** * Mail receive server config * 邮件接收服务器配置信息 */ private final MailConfig.ServerConfig receiveConfig; /** * e-mail receive operator * 电子邮件接收器 */ private final ReceiveOperator receiveOperator; /** * Attaches the file storage path * 附件文件的保存地址 */ private final String storagePath; /** * x509 certificate Using for email signature verify * x509证书用于电子邮件签名验证 */ private final X509Certificate x509Certificate; /** * private key Using for email signature * 私有密钥用于电子邮件签名 */ private final PrivateKey privateKey; /** *

Private constructor for E-Mail Agent

*

电子邮件代理的私有构造方法

* * @param mailConfig Mail configure information define * 邮件配置信息定义 */ private Agent(final MailConfig mailConfig) { this.userName = mailConfig.getUserName().toLowerCase(); this.passWord = SecureFactory.decrypt(mailConfig.getSecureName(), mailConfig.getPassword()); if (mailConfig.getSendConfig() == null || !MailProtocol.SMTP.equals(mailConfig.getSendConfig().getProtocolOption())) { this.sendConfig = null; this.sendOperator = null; } else { this.sendConfig = mailConfig.getSendConfig(); this.sendOperator = new SMTPProtocol(mailConfig.getSecureName(), mailConfig.getProxyConfig()); } if (mailConfig.getReceiveConfig() == null) { this.receiveConfig = null; this.receiveOperator = null; } else { this.receiveConfig = mailConfig.getReceiveConfig(); switch (this.receiveConfig.getProtocolOption()) { case IMAP: this.receiveOperator = new IMAPProtocol(mailConfig.getSecureName(), mailConfig.getProxyConfig()); break; case POP3: this.receiveOperator = new POP3Protocol(mailConfig.getSecureName(), mailConfig.getProxyConfig()); break; default: this.receiveOperator = null; break; } } this.storagePath = mailConfig.getStoragePath(); this.x509Certificate = StringUtils.notBlank(mailConfig.getCertificate()) ? CertificateUtils.x509(StringUtils.base64Decode(mailConfig.getCertificate())) : null; this.privateKey = StringUtils.notBlank(mailConfig.getPrivateKey()) ? CertificateUtils.privateKey("RSA", StringUtils.base64Decode(mailConfig.getPrivateKey())) : null; } /** *

Send E-Mail

*

发送电子邮件

* * @param mailObject E-Mail object * 电子邮件信息 * * @return Process result * 操作结果 */ public boolean sendMail(final MailObject mailObject) { if (this.sendOperator == null) { // Not config send server return Boolean.FALSE; } try { Properties properties = this.sendOperator.readConfig(this.sendConfig); if (StringUtils.notBlank(this.userName)) { properties.setProperty("mail.smtp.from", this.userName); } Session session = Session.getDefaultInstance(properties, new DefaultAuthenticator(this.userName, this.passWord)); session.setDebug(this.logger.isDebugEnabled()); if (StringUtils.isEmpty(mailObject.getSendAddress())) { mailObject.setSendAddress(this.userName); } Transport.send(convert(session, mailObject, this.x509Certificate, this.privateKey)); return Boolean.TRUE; } catch (MessagingException | MailException e) { this.logger.error("Send_Mail_Error"); if (this.logger.isDebugEnabled()) { this.logger.debug("Stack_Message_Error", e); } return Boolean.FALSE; } } /** *

Read folder name list from default folder

*

从默认文件夹中读取包含的文件夹名称列表

* * @return folder name list * 文件夹名称列表 */ public List folderList() { List folderList = new ArrayList<>(); try (Store store = connect()) { Folder defaultFolder = store.getDefaultFolder(); if (defaultFolder != null) { for (Folder folder : defaultFolder.list()) { folderList.add(folder.getFullName()); } } } catch (Exception e) { this.logger.error("Folders_Mail_Error"); if (this.logger.isDebugEnabled()) { this.logger.debug("Stack_Message_Error", e); } } return folderList; } /** *

Read mail count from inbox

*

读取收件箱中的邮件数量

* * @return Mail count * 邮件数量 */ public int mailCount() { return this.mailCount(Globals.DEFAULT_EMAIL_FOLDER_INBOX); } /** *

Read mail count from given folder name

*

读取给定文件夹中的邮件数量

* * @param folderName folder name * 文件夹名称 * * @return Mail count * 邮件数量 */ public int mailCount(final String folderName) { if (this.receiveOperator == null) { // Not configs receive server return Globals.DEFAULT_VALUE_INT; } try (Store store = connect(); Folder folder = openReadOnlyFolder(store, folderName)) { if (folder.exists() && folder.isOpen()) { return folder.getMessageCount(); } } catch (Exception e) { this.logger.error("Receive_Mail_Error"); if (this.logger.isDebugEnabled()) { this.logger.debug("Stack_Message_Error", e); } } return Globals.DEFAULT_VALUE_INT; } /** *

Read mail UID list from inbox

*

读取收件箱中的邮件唯一标识列表

* * @return Mail UID list * 邮件唯一标识列表 */ public List mailList() { return this.mailList(Globals.DEFAULT_EMAIL_FOLDER_INBOX); } /** *

Read mail UID list from given folder name

*

读取给定文件夹中的邮件唯一标识列表

* * @param folderName folder name * 文件夹名称 * * @return Mail UID list * 邮件唯一标识列表 */ public List mailList(final String folderName) { return mailList(folderName, Globals.DEFAULT_VALUE_INT, Globals.DEFAULT_VALUE_INT); } /** *

Read mail UID list from given folder name limit index from begin to end

*

读取给定文件夹中的部分邮件唯一标识列表,从给定的起始索引号到终止索引号

* * @param folderName folder name * 文件夹名称 * @param begin Begin index * 起始索引号 * @param end End index * 终止索引号 * * @return Mail UID list * 邮件唯一标识列表 */ public List mailList(final String folderName, final int begin, final int end) { if (this.receiveOperator == null || end < begin) { return Collections.emptyList(); } try (Store store = connect(); Folder folder = openReadOnlyFolder(store, folderName)) { if (!folder.exists() || !folder.isOpen()) { return Collections.emptyList(); } int totalCount = folder.getMessageCount(); List mailList = new ArrayList<>(); int start = Math.max(1, begin); int stop = (end < 0) ? totalCount : Math.min(totalCount, end); for (Message message : folder.getMessages(start, stop)) { mailList.add(this.receiveOperator.readUID(folder, message)); } return mailList; } catch (Exception e) { this.logger.error("Receive_Mail_Error"); if (this.logger.isDebugEnabled()) { this.logger.debug("Stack_Message_Error", e); } } return Collections.emptyList(); } /** *

Read mail information from given folder name and UID

*

根据给定的文件夹名和邮件唯一标识读取邮件信息

* * @param folderName folder name * 文件夹名称 * @param uid E-Mail UID * 邮件唯一标识 * * @return Read MailObject instance * 读取的电子邮件信息实例对象 */ public MailObject readMail(final String folderName, final String uid) { return this.readMail(folderName, uid, Boolean.FALSE); } /** *

Read mail content information from given folder name and UID

*

根据给定的文件夹名和邮件唯一标识读取邮件详细信息

* * @param folderName folder name * 文件夹名称 * @param uid E-Mail UID * 邮件唯一标识 * @param detail Read detail status * 读取全部信息状态 * * @return Read MailObject instance * 读取的电子邮件信息实例对象 */ public MailObject readMail(final String folderName, final String uid, final boolean detail) { if (this.receiveOperator == null) { return null; } try (Store store = connect(); Folder folder = openReadOnlyFolder(store, folderName)) { if (!folder.exists() || !folder.isOpen()) { return null; } Message message = this.receiveOperator.readMessage(folder, uid); if (message != null) { return receiveMessage((MimeMessage) message, detail); } } catch (Exception e) { this.logger.error("Receive_Mail_Error"); if (this.logger.isDebugEnabled()) { this.logger.debug("Stack_Message_Error", e); } } return null; } /** *

Read mail content information list from given folder name and UID array

*

根据给定的文件夹名和邮件唯一标识数组读取邮件详细信息

* * @param folderName folder name * 文件夹名称 * @param uidArrays E-Mail UID array * 邮件唯一标识数组 * * @return Read MailObject instance list * 读取的电子邮件信息实例对象列表 */ public List readMailList(final String folderName, final String... uidArrays) { List mailList = new ArrayList<>(); if (this.receiveOperator == null) { return mailList; } try (Store store = connect(); Folder folder = openReadOnlyFolder(store, folderName)) { if (!folder.exists() || !folder.isOpen()) { return mailList; } this.receiveOperator.readMessages(folder, uidArrays) .forEach(message -> Optional.ofNullable(receiveMessage((MimeMessage) message, Boolean.FALSE)) .ifPresent(mailList::add)); } catch (Exception e) { this.logger.error("Receive_Mail_Error"); if (this.logger.isDebugEnabled()) { this.logger.debug("Stack_Message_Error", e); } } return mailList; } /** *

Set mails status as read with given folder name and UID array

*

根据给定的文件夹名和邮件唯一标识数组,将对应的邮件置为已读状态

* * @param folderName folder name * 文件夹名称 * @param uidArrays E-Mail UID array * 邮件唯一标识数组 * * @return Process result * 操作结果 */ public boolean readMails(final String folderName, final String... uidArrays) { return this.flagMailsStatus(Flags.Flag.SEEN, Boolean.TRUE, folderName, uidArrays); } /** *

Set mails status as unread with given folder name and UID array

*

根据给定的文件夹名和邮件唯一标识数组,将对应的邮件置为未读状态

* * @param folderName folder name * 文件夹名称 * @param uidArrays E-Mail UID array * 邮件唯一标识数组 * * @return Process result * 操作结果 */ public boolean unreadMails(final String folderName, final String... uidArrays) { return this.flagMailsStatus(Flags.Flag.SEEN, Boolean.FALSE, folderName, uidArrays); } /** *

Set mails status as answer with given folder name and UID array

*

根据给定的文件夹名和邮件唯一标识数组,将对应的邮件置为已回复状态

* * @param folderName folder name * 文件夹名称 * @param uidArrays E-Mail UID array * 邮件唯一标识数组 * * @return Process result * 操作结果 */ public boolean answerMails(final String folderName, final String... uidArrays) { return this.flagMailsStatus(Flags.Flag.ANSWERED, Boolean.TRUE, folderName, uidArrays); } /** *

Delete mails by given folder name and UID array

*

根据给定的文件夹名和邮件唯一标识数组,将对应的邮件转移到回收站

* * @param folderName folder name * 文件夹名称 * @param uidArrays E-Mail UID array * 邮件唯一标识数组 * * @return Process result * 操作结果 */ public boolean deleteMails(final String folderName, final String... uidArrays) { return this.flagMailsStatus(Flags.Flag.DELETED, Boolean.TRUE, folderName, uidArrays); } /** *

Recovery mails by given folder name and UID array

*

根据邮件唯一标识数组,将对应的邮件置从回收站转移到给定的文件夹

* Set mails status as read by uid list * * @param folderName folder name * 文件夹名称 * @param uidArrays E-Mail UID array * 邮件唯一标识数组 * * @return Process result * 操作结果 */ public boolean recoverMails(final String folderName, final String... uidArrays) { if (this.receiveOperator == null) { return Boolean.FALSE; } try (Store store = connect(); Folder folder = openFolder(store, Boolean.FALSE, folderName); Folder inbox = openFolder(store, Boolean.FALSE, Globals.DEFAULT_EMAIL_FOLDER_INBOX)) { if (!folder.exists() || !folder.isOpen()) { return Boolean.FALSE; } List messageList = this.receiveOperator.readMessages(folder, uidArrays); folder.copyMessages(messageList.toArray(new Message[0]), inbox); return Boolean.TRUE; } catch (Exception e) { this.logger.error("Set_Status_Mail_Error"); if (this.logger.isDebugEnabled()) { this.logger.debug("Stack_Message_Error", e); } return Boolean.FALSE; } } /** *

Set mails status as flag with given folder name and UID array

*

根据给定的文件夹名和邮件唯一标识数组,将对应的邮件置为标记状态

* * @param folderName folder name * 文件夹名称 * @param uidArrays E-Mail UID array * 邮件唯一标识数组 * * @return Process result * 操作结果 */ public boolean flagMails(final String folderName, final String... uidArrays) { return this.flagMailsStatus(Flags.Flag.FLAGGED, Boolean.TRUE, folderName, uidArrays); } /** *

Set mails status as unflag with given folder name and UID array

*

根据给定的文件夹名和邮件唯一标识数组,将对应的邮件置为未标记状态

* * @param folderName folder name * 文件夹名称 * @param uidArrays E-Mail UID array * 邮件唯一标识数组 * * @return Process result * 操作结果 */ public boolean unflagMails(final String folderName, final String... uidArrays) { return this.flagMailsStatus(Flags.Flag.FLAGGED, Boolean.FALSE, folderName, uidArrays); } /** *

Set mails status with parameters

*

根据参数信息设置对应的邮件状态

* * @param flag Flag code * 标记类型 * @param status Flag status * 标记状态 * @param uidArrays E-Mail UID array * 邮件唯一标识数组 * * @return Process result * 操作结果 */ private boolean flagMailsStatus(final Flags.Flag flag, final boolean status, final String folderName, final String... uidArrays) { if (this.receiveOperator == null) { return Boolean.FALSE; } try (Store store = connect(); Folder folder = openFolder(store, Boolean.FALSE, folderName)) { if (!folder.exists() || !folder.isOpen()) { return Boolean.FALSE; } List messageList = this.receiveOperator.readMessages(folder, uidArrays); for (Message message : messageList) { message.setFlag(flag, status); } return true; } catch (Exception e) { this.logger.error("Set_Status_Mail_Error"); if (this.logger.isDebugEnabled()) { this.logger.debug("Stack_Message_Error", e); } return Boolean.FALSE; } } /** *

Connect to mail server

*

连接到电子邮件服务器

* * @return Store instance * Store实例对象 * * @throws MessagingException * If connect failed * 如果连接失败 */ private Store connect() throws MessagingException { Properties properties = this.receiveOperator.readConfig(this.receiveConfig); Session session = Session.getInstance(properties, new DefaultAuthenticator(this.userName, this.passWord)); session.setDebug(this.logger.isDebugEnabled()); Store store = session.getStore(properties.getProperty("mail.store.protocol")); store.connect(this.receiveConfig.getHostName(), this.receiveConfig.getHostPort(), this.userName, this.passWord); return store; } /** *

Verify e-mail signature

*

验证电子邮件签名

* * @param mimeMessage E-Mail MimeMessage instance * 电子邮件信息实例对象 * @return Verify result * 验证结果 */ @SuppressWarnings("unchecked") private boolean verifyMessage(final MimeMessage mimeMessage) { try { MimeMessage signedMessage = new MimeMessage(mimeMessage); SMIMESignedParser signedParser; if (signedMessage.isMimeType("multipart/signed")) { signedParser = new SMIMESignedParser(new JcaDigestCalculatorProviderBuilder().build(), (MimeMultipart) signedMessage.getContent()); } else if (signedMessage.isMimeType("application/pkcs7-mime")) { signedParser = new SMIMESignedParser(new JcaDigestCalculatorProviderBuilder().build(), signedMessage); } else { return Boolean.TRUE; } org.bouncycastle.util.Store certificates = signedParser.getCertificates(); for (SignerInformation signerInformation : signedParser.getSignerInfos().getSigners()) { Collection certCollection = certificates.getMatches(signerInformation.getSID()); X509Certificate certificate = new JcaX509CertificateConverter().setProvider("BC") .getCertificate((X509CertificateHolder) certCollection.iterator().next()); try { SignerInformationVerifier signerInformationVerifier = new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(certificate); return signerInformation.verify(signerInformationVerifier); } catch (Exception e) { this.logger.error("Verify_Signature_Mail_Error"); if (this.logger.isDebugEnabled()) { this.logger.debug("Stack_Message_Error", e); } } } } catch (Exception e) { this.logger.error("Verify_Signature_Mail_Error"); if (this.logger.isDebugEnabled()) { this.logger.debug("Stack_Message_Error", e); } } return Boolean.FALSE; } /** *

Parse MimeMessage instance to MailObject instance

*

解析电子邮件MIME信息实例对象并转换为电子邮件信息实例对象

* * @param mimeMessage E-Mail MimeMessage instance * 电子邮件MIME信息实例对象 * @param detail Read detail status * 读取全部信息状态 * * @return Read MailObject instance * 读取的电子邮件信息实例对象 */ private MailObject receiveMessage(final MimeMessage mimeMessage, final boolean detail) { if (!verifyMessage(mimeMessage)) { return null; } try { MailObject mailObject = new MailObject(); List receiveList = new ArrayList<>(); Address[] allRecipients = mimeMessage.getAllRecipients(); if (allRecipients == null) { return null; } Arrays.stream(allRecipients) .filter(InternetAddress.class::isInstance) .forEach(address -> receiveList.add(((InternetAddress) address).getAddress().toLowerCase())); if (!receiveList.contains(this.userName)) { throw new MessagingException("Current account not in receive list! "); } mailObject.setReceiveAddress(receiveList); Folder folder = mimeMessage.getFolder(); if (folder instanceof POP3Folder) { mailObject.setUid(((POP3Folder) folder).getUID(mimeMessage)); } else if (folder instanceof IMAPFolder) { mailObject.setUid(Long.valueOf(((IMAPFolder) folder).getUID(mimeMessage)).toString()); } String subject = mimeMessage.getSubject(); if (StringUtils.notBlank(subject)) { mailObject.setSubject(MimeUtility.decodeText(subject)); } else { mailObject.setSubject(Globals.DEFAULT_VALUE_STRING); } mailObject.setSendDate(mimeMessage.getSentDate()); mailObject.setSendAddress(MimeUtility.decodeText(InternetAddress.toString(mimeMessage.getFrom()))); if (detail) { // Read mail cc address Optional.ofNullable((InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.CC)) .ifPresent(ccAddress -> { List ccList = new ArrayList<>(); Arrays.asList(ccAddress).forEach(address -> ccList.add(address.getAddress())); mailObject.setCcAddress(ccList); }); // Read mail bcc address Optional.ofNullable((InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.BCC)) .ifPresent(bccAddress -> { List bccList = new ArrayList<>(); Arrays.asList(bccAddress).forEach(address -> bccList.add(address.getAddress())); mailObject.setBccAddress(bccList); }); // Read mail content message StringBuilder contentBuffer = new StringBuilder(); readMailContent(mimeMessage, contentBuffer); mailObject.setContent(contentBuffer.toString()); mailObject.setContentType(mimeMessage.getContentType()); mailObject.setAttachFiles(getMailAttachment(mimeMessage)); } return mailObject; } catch (MessagingException | IOException e) { this.logger.error("Receive_Mail_Error"); if (this.logger.isDebugEnabled()) { this.logger.debug("Stack_Message_Error", e); } return null; } } /** *

Read attachment files from given part of e-mail MIME information

*

从给定的电子邮件MIME信息中读取附件文件

* * @param part part of e-mail MIME information * 电子邮件MIME信息 * * @return Read file path list * 读取的附件文件路径列表 * * @throws MessagingException * If an error occurs when read attachment information * 当读取附件数据时出现异常 * @throws IOException * If an error occurs when save file to local * 当写入数据到本地文件时出现异常 */ private List getMailAttachment(final Part part) throws MessagingException, IOException { List saveFiles = new ArrayList<>(); if (StringUtils.isEmpty(this.storagePath)) { throw new IOException("Save attach file path error! "); } if (part.isMimeType(Globals.DEFAULT_CONTENT_TYPE_MULTIPART)) { Multipart multipart = (Multipart) part.getContent(); int count = multipart.getCount(); for (int i = 0; i < count; i++) { Optional.ofNullable(multipart.getBodyPart(i)) .ifPresent(bodyPart -> this.readBodyPart(bodyPart, saveFiles)); } } return saveFiles; } /** *

Read attachment files from given body part of MIME information

*

从给定的电子邮件MIME信息体中读取附件文件

* * @param bodyPart body part of MIME information * 电子邮件MIME信息体 * @param saveFiles Saved file path list * 已保存的文件路径列表 */ private void readBodyPart(final Part bodyPart, final List saveFiles) { try { if (bodyPart.getHeader("Content-ID") != null && bodyPart.getHeader("Content-ID").length > 0) { return; } if (StringUtils.notBlank(bodyPart.getFileName())) { String disposition = bodyPart.getDisposition(); if (disposition != null && (disposition.equals(Part.ATTACHMENT) || disposition.equals(Part.INLINE))) { String savePath = this.storagePath + Globals.DEFAULT_PAGE_SEPARATOR + MimeUtility.decodeText(bodyPart.getFileName()); if (!savePath.toLowerCase().endsWith("p7s")) { boolean saveFile = FileUtils.saveFile(bodyPart.getInputStream(), savePath); if (saveFile) { saveFiles.add(savePath); } } } else if (bodyPart.isMimeType(Globals.DEFAULT_CONTENT_TYPE_MULTIPART)) { saveFiles.addAll(getMailAttachment(bodyPart)); } } } catch (MessagingException | IOException e) { this.logger.error("Attachment_Receive_Mail_Error"); if (this.logger.isDebugEnabled()) { this.logger.debug("Stack_Message_Error", e); } } } } /** *

Add signature to MailObject instance and convert to MimeMessage instance

*

添加电子签名到电子邮件信息并转换为电子邮件MIME信息实例对象

* * @param session Current session * 当前的事务链接 * @param mailObject Read MailObject instance * 读取的电子邮件信息实例对象 * @param x509Certificate x509 certificate * x509证书 * @param privateKey private key * 私有密钥 * * @return Converted MimeMessage instance * 转换后的电子邮件MIME信息实例对象 * * @throws MailException * If an error occurs when process convert * 当转换数据时出现异常 * * @throws MessagingException * If an error occurs when process convert * 当转换数据时出现异常 */ private static MimeMessage convert(final Session session, final MailObject mailObject, final X509Certificate x509Certificate, final PrivateKey privateKey) throws MailException, MessagingException { MimeMessage message = new MimeMessage(session); message.setSubject(mailObject.getSubject(), mailObject.getCharset()); MimeMultipart mimeMultipart = new MimeMultipart(); if (mailObject.getAttachFiles() != null) { for (String attachment : mailObject.getAttachFiles()) { MimeBodyPart mimeBodyPart = new MimeBodyPart(); File file; try { file = FileUtils.getFile(attachment); } catch (FileNotFoundException e) { throw new MailException(0x0000000E0005L, "Attachment_File_Not_Found_Error", e); } DataSource dataSource = new FileDataSource(file); mimeBodyPart.setFileName(StringUtils.getFilename(attachment)); mimeBodyPart.setDataHandler(new DataHandler(dataSource)); mimeMultipart.addBodyPart(mimeBodyPart, mimeMultipart.getCount()); } } if (mailObject.getIncludeFiles() != null) { List includeFiles = mailObject.getIncludeFiles(); for (String filePath : includeFiles) { File file; MimeBodyPart mimeBodyPart; try { file = FileUtils.getFile(filePath); String fileName = StringUtils.getFilename(filePath); mimeBodyPart = new MimeBodyPart(); DataHandler dataHandler = new DataHandler(new ByteArrayDataSource(file.toURI().toURL().openStream(), Globals.DEFAULT_CONTENT_TYPE_BINARY)); mimeBodyPart.setDataHandler(dataHandler); mimeBodyPart.setFileName(fileName); mimeBodyPart.setHeader("Content-ID", fileName); } catch (Exception e) { throw new MailException(0x0000000E0006L, "Attachment_File_Error", e); } mimeMultipart.addBodyPart(mimeBodyPart, mimeMultipart.getCount()); } } if (StringUtils.notBlank(mailObject.getContent())) { MimeBodyPart mimeBodyPart = new MimeBodyPart(); mimeBodyPart.setContent(mailObject.getContent(), mailObject.getContentType() + "; charset=" + mailObject.getCharset()); mimeMultipart.addBodyPart(mimeBodyPart, mimeMultipart.getCount()); } if (x509Certificate != null && privateKey != null) { message.setContent(mimeMultipart); try { // Generate signature attribute ASN1EncodableVector signatureAttribute = new ASN1EncodableVector(); SMIMECapabilityVector capabilityVector = new SMIMECapabilityVector(); capabilityVector.addCapability(SMIMECapability.aES256_CBC); capabilityVector.addCapability(SMIMECapability.dES_CBC); capabilityVector.addCapability(SMIMECapability.rC2_CBC, 128); signatureAttribute.add(new SMIMECapabilitiesAttribute(capabilityVector)); signatureAttribute.add(new SMIMEEncryptionKeyPreferenceAttribute(SMIMEUtil.createIssuerAndSerialNumberFor(x509Certificate))); List certificateList = Collections.singletonList(x509Certificate); JcaCertStore certStore = new JcaCertStore(certificateList); SignerInfoGenerator signerInfoGenerator = new JcaSimpleSignerInfoGeneratorBuilder() .setProvider("BC") .setSignedAttributeGenerator(new AttributeTable(signatureAttribute)) .build("SHA1withRSA", privateKey, x509Certificate); SMIMESignedGenerator generator = new SMIMESignedGenerator(); generator.addSignerInfoGenerator(signerInfoGenerator); generator.addCertificates(certStore); MimeMultipart signedMimeMultipart = generator.generate(message); message.setContent(signedMimeMultipart, signedMimeMultipart.getContentType()); } catch (CertificateEncodingException | CertificateParsingException | OperatorCreationException | SMIMEException e) { throw new MailException(0x0000000E0007L, "Signature_Mail_Error", e); } } else { message.setContent(mimeMultipart, mimeMultipart.getContentType()); } message.setFrom(new InternetAddress(mailObject.getSendAddress())); if (mailObject.getReceiveAddress() == null || mailObject.getReceiveAddress().isEmpty()) { throw new MailException(0x0000000E0008L, "Unknown_Receive_Address_Mail_Error"); } StringBuilder receiveAddress = new StringBuilder(); mailObject.getReceiveAddress().forEach(address -> receiveAddress.append(",").append(address)); message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(receiveAddress.substring(1))); if (mailObject.getCcAddress() != null && !mailObject.getCcAddress().isEmpty()) { StringBuilder ccAddress = new StringBuilder(); mailObject.getCcAddress().forEach(address -> ccAddress.append(",").append(address)); message.setRecipients(Message.RecipientType.CC, InternetAddress.parse(ccAddress.substring(1))); } if (mailObject.getBccAddress() != null && !mailObject.getBccAddress().isEmpty()) { StringBuilder bccAddress = new StringBuilder(); mailObject.getBccAddress().forEach(address -> bccAddress.append(",").append(address)); message.setRecipients(Message.RecipientType.BCC, InternetAddress.parse(bccAddress.substring(1))); } if (mailObject.getReplyAddress() != null && !mailObject.getReplyAddress().isEmpty()) { StringBuilder replyAddress = new StringBuilder(); mailObject.getReplyAddress().forEach(address -> replyAddress.append(",").append(address)); message.setReplyTo(InternetAddress.parse(replyAddress.substring(1))); } else { message.setReplyTo(InternetAddress.parse(mailObject.getSendAddress())); } message.setSentDate(mailObject.getSendDate() == null ? new Date() : mailObject.getSendDate()); return message; } /** *

Open folder from Store instance by given folder name in read only mode

*

在只读模式中打开给定的Store实例对象中的文件夹

* * @param store Store instance * Store实例对象 * @param folderName folder name * 文件夹名称 * * @return Opened Folder instance * 打开的文件夹实例对象 * * @throws MessagingException * If an error occurs when process open * 当读取数据时出现异常 */ private static Folder openReadOnlyFolder(final Store store, final String folderName) throws MessagingException { return openFolder(store, Boolean.TRUE, folderName); } /** *

Open folder from Store instance by given folder name and mode

*

使用给定的模式中打开给定的Store实例对象中的文件夹

* * @param store Store instance * Store实例对象 * @param readOnly Read only status * 只读模式状态 * @param folderName folder name * 文件夹名称 * * @return Opened Folder instance * 打开的文件夹实例对象 * * @throws MessagingException * If an error occurs when process open * 当读取数据时出现异常 */ private static Folder openFolder(final Store store, final boolean readOnly, final String folderName) throws MessagingException { Folder folder = store.getFolder(folderName); folder.open(readOnly ? Folder.READ_ONLY : Folder.READ_WRITE); return folder; } /** *

Read mail content information

*

读取电子邮件详细信息

* * @param part part of e-mail MIME information * 电子邮件MIME信息 * @param contentBuffer Content information buffer * 详细信息输出缓冲器 * * @throws MessagingException * If an error occurs when process read * 当读取信息时出现异常 * @throws IOException * If an error occurs when append content information to buffer * 当追加详细信息到输出缓冲器时出现异常 */ private static void readMailContent(final Part part, final StringBuilder contentBuffer) throws MessagingException, IOException { String contentType = part.getContentType(); int nameIndex = contentType.indexOf("name"); if (contentBuffer == null) { throw new IOException(); } if (part.isMimeType(Globals.DEFAULT_CONTENT_TYPE_TEXT) && (nameIndex == -1)) { contentBuffer.append(part.getContent().toString()); } else if (part.isMimeType(Globals.DEFAULT_CONTENT_TYPE_HTML) && (nameIndex == -1)) { contentBuffer.append(part.getContent().toString()); } else if (part.isMimeType(Globals.DEFAULT_CONTENT_TYPE_MULTIPART)) { Multipart multipart = (Multipart) part.getContent(); int count = multipart.getCount(); for (int i = 0; i < count; i++) { readMailContent(multipart.getBodyPart(i), contentBuffer); } } else if (part.isMimeType(Globals.DEFAULT_CONTENT_TYPE_MESSAGE_RFC822)) { readMailContent((Part) part.getContent(), contentBuffer); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy