private static final Logger log = LoggerFactory.getLogger(ReceiveMail.class);
// 账号
@Value("${mail.connect.username}")
private String user;
// 密码
@Value("${mail.connect.password}")
private String password;
@Autowired
private MailUtil mailUtil;
@Autowired
private ITmsCompanyService iTmsCompanyService;
@Autowired
private IOrderFileService orderFileService;
@Autowired
private ISysUserService sysUserService;
@Test
public void readMail() throws Exception {
AjaxResult ajaxResult =null;
Message[] messages = mailUtil.getPopMessages(user,password);
for (Message message : messages) {
//获取发送地址
String addressUser = mailUtil.getFrom(message);
List<TmsCompany> list= iTmsCompanyService.selectByMail(addressUser);
if (list.size()<=0) {
log.info("当前邮件的发件人{}不是我们要监控的对象", addressUser);
continue ;
}
Long companyId = list.get(0).getCompanyId();
String companyName = list.get(0).getCompanyName();
if (!mailUtil.isContainAttach((Part) message)) {
log.info("发件人满足要求但是附件为空,不满足我们监控的需求!");
continue;
}
try {
List<MailAttachment> mailAttachments = new ArrayList<>();
mailUtil.getAttachment(message, mailAttachments);
for (MailAttachment mailAttachment : mailAttachments) {
//检查文件命名是否无误
boolean b = mailUtil.checkoutFileName(mailAttachment.getName(), companyId.toString());
if (b) {
log.info("附件命名有误,导入订单操作取消!");
continue;
}
if (mailAttachment.getInputStream()!=null) {
List<SysUser> sysUsers = sysUserService.selectByCompanyId(companyId);
if (sysUsers.size()<=0) {
continue;
}
//将文件从邮箱附件保存到本地
File fileExcel = mailUtil.saveFile(mailAttachment, companyId);
}
}
}
catch (Exception ignore) {
ignore.printStackTrace();
}
}
mailUtil.close();
}
邮件工具类
import com.alibaba.fastjson.JSONObject;
import com.fanlyun.admin.biz.mail.MailAttachment;
import com.fanlyun.common.constant.Constants;
import com.sun.mail.imap.IMAPFolder;
import com.sun.mail.imap.IMAPStore;
import com.sun.mail.pop3.POP3Folder;
import com.sun.mail.pop3.POP3Store;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.mail.*;
import javax.mail.internet.*;
import javax.mail.search.*;
import java.io.*;
import java.util.*;
/**
* @author jiangyw
* @date 2019/1/7 19:29
* <p>
* 处理邮件工具类
* 接收/发送服务器根据不同邮箱有不同的地址
* 在邮箱设置里都可找到
*/
@Component
public class MailUtil {
private static final Logger log = LoggerFactory.getLogger(MailUtil.class);
// 发送服务器
private static final String SEND_SMTP_HOST = "smtp.exmail.qq.com";
private static final int SEND_SMTP_PORT = 465;
// 接收服务器
private static final String RECEIVE_IMAP_HOST = "imap.exmail.qq.com";
private static final int RECEIVE_IMAP_PORT = 993;
private static final String RECEIVE_POP_HOST = "pop.exmail.qq.com";
private static final int RECEIVE_POP_PORT = 110;
private IMAPFolder imapFolder = null;
private IMAPStore imapStore = null;
private POP3Store pop3Store = null;
private POP3Folder pop3Folder = null;
//附件保存路径
@Value("${mail.receive.saveUrl}")
private String saveUrl;
//附件保存路径
@Value("${mail.receive.time}")
private int time;
/**
* 将附件保存下来
*
* @param
* @param companyId
* @throws IOException
*/
public File saveFile(MailAttachment mailAttachment, Long companyId) throws IOException {
String fileName = mailAttachment.getName();
InputStream inputStream = mailAttachment.getInputStream();
File file = new File(saveUrl + companyId);
//如果文件夹不存在则创建
if (!file.exists() && !file.isDirectory()) {
file.mkdir();
}
//文件保存路径
long l = System.currentTimeMillis();
String[] split = fileName.split("\\.");
String pathName=saveUrl +companyId+File.separator+ split[0]+"_"+l+"."+split[1];
File fileExcel = new File(pathName);
FileOutputStream outputStream = new FileOutputStream(fileExcel);
int len;
byte[] bytes = new byte[1024];
while ((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, len);
outputStream.flush();
}
inputStream.close();
outputStream.close();
return fileExcel;
}
/***
* 判断文件命名是否符合条件
* @param fileName
* @param companyId
* @return
*/
public boolean checkoutFileName(String fileName, String companyId) {
boolean pan = false;
if (!fileName.endsWith(Constants.XLSX)) {
log.info("该附件【{}】文件格式不符合条件,无法导入", fileName);
pan = true;
}
String[] s = null;
try {
String[] split = fileName.split("\\.");
fileName = split[0];
s = fileName.split(Constants.EMAIL_UNDERLINE);
if (!s[0].equals(Constants.EMAIL_PREFIX)) {
log.info("该附件【{}】文件命名不符合条件,前缀命名不符合规范,无法导入", fileName);
pan = true;
}
if (!s[1].equals(companyId)) {
log.info("该附件【{}】文件命名不符合条件,公司Id查询失败,无法导入", fileName);
pan = true;
}
} catch (Exception e) {
log.info("该附件【{}】文件命名不符合条件,无法导入", fileName);
} finally {
return pan;
}
}
/**
* 获取附件
* 只获取附件里的
* 邮件内容里的附件(图片等)忽略
*
* @param part 邮件中多个组合体中的其中一个组合体
* @param list 附件容器
* @throws UnsupportedEncodingException
* @throws MessagingException
* @throws FileNotFoundException
* @throws IOException
*/
public void getAttachment(Part part, List<MailAttachment> list) throws UnsupportedEncodingException, MessagingException,
FileNotFoundException, IOException {
if (part.isMimeType("multipart/*")) {
Multipart multipart = (Multipart) part.getContent(); //复杂体邮件
//复杂体邮件包含多个邮件体
int partCount = multipart.getCount();
for (int i = 0; i < partCount; i++) {
//获得复杂体邮件中其中一个邮件体
BodyPart bodyPart = multipart.getBodyPart(i);
//某一个邮件体也有可能是由多个邮件体组成的复杂体
String disposition = bodyPart.getDisposition();
if (disposition != null && (disposition.equalsIgnoreCase(Part.ATTACHMENT) || disposition.equalsIgnoreCase(Part.INLINE))) {
InputStream is = bodyPart.getInputStream();
// 附件名通过MimeUtility解码,否则是乱码
String name = MimeUtility.decodeText(bodyPart.getFileName());
list.add(new MailAttachment(name, is));
} else if (bodyPart.isMimeType("multipart/*")) {
log.info("子邮件里面的附件");
getAttachment(bodyPart, list);
} else {
String contentType = bodyPart.getContentType();
if (contentType.contains("name") || contentType.contains("application")) {
}
}
}
} else if (part.isMimeType("message/rfc822")) {
getAttachment((Part) part.getContent(), list);
}
}
/**
* @param
* @param part
* @return java.io.InputStream
* @author FeianLing
* @date 2019/8/20
* @desc 获取文件输入流
*/
private void getFileInputStream(Part part, Map<String, InputStream> inputStreamMap) throws Exception {
String fileName;
if (part.isMimeType("multipart/*")) {
Multipart mp = (Multipart) part.getContent();
for (int i = 0; i < mp.getCount(); i++) {
BodyPart mPart = mp.getBodyPart(i);
String disposition = mPart.getDisposition();
if ((disposition != null)
&& ((disposition.equals(Part.ATTACHMENT)) || (disposition
.equals(Part.INLINE)))) {
fileName = mPart.getFileName();
if (fileName.toLowerCase().indexOf("gb2312") != -1) {
fileName = MimeUtility.decodeText(fileName);
}
if (checkFileName(fileName)) {
inputStreamMap.put(fileName, mPart.getInputStream());
}
} else if (mPart.isMimeType("multipart/*")) {
log.info("子邮件里面的附件");
getFileInputStream(mPart, inputStreamMap);
} else {
fileName = mPart.getFileName();
if ((fileName != null)
&& (fileName.toLowerCase().indexOf("GB2312") != -1)) {
fileName = MimeUtility.decodeText(fileName);
if (checkFileName(fileName)) {
inputStreamMap.put(fileName, mPart.getInputStream());
}
}
}
}
} else if (part.isMimeType("message/rfc822")) {
getFileInputStream((Part) part.getContent(), inputStreamMap);
}
}
/**
* 获得邮件文本内容
*
* @param part 邮件体
* @param textContent 存储邮件文本内容的字符串
* @param htmlContent 存储邮件html内容的字符串
* @throws MessagingException
* @throws IOException
*/
public void getMailTextContent(Part part, StringBuffer textContent, StringBuffer htmlContent) throws MessagingException, IOException {
//如果是文本类型的附件,通过getContent方法可以取到文本内容,但这不是我们需要的结果,所以在这里要做判断
boolean isContainTextAttach = part.getContentType().indexOf("name") > 0;
if (part.isMimeType("text/*") && !isContainTextAttach) {
String contentType = part.getContentType();
if (contentType.startsWith("TEXT/PLAIN") || contentType.startsWith("text/plain")) {
textContent.append(part.getContent().toString());
}
if (contentType.startsWith("TEXT/HTML") || contentType.startsWith("text/html")) {
htmlContent.append(part.getContent().toString());
}
} else if (part.isMimeType("message/rfc822")) {
getMailTextContent((Part) part.getContent(), textContent, htmlContent);
} else if (part.isMimeType("multipart/*")) {
Multipart multipart = (Multipart) part.getContent();
int partCount = multipart.getCount();
for (int i = 0; i < partCount; i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
getMailTextContent(bodyPart, textContent, htmlContent);
}
}
}
/***
* 获取邮件主题
* @param message
* @return
* @throws MessagingException
*/
public String getSubject(Message message) throws MessagingException {
return message.getSubject();
}
/**
* 通过pop3协议获取邮件信息
* pop3协议下只能通过sentDate来查询
* receivedDate都为null
*
* @return Message[]
* @throws MessagingException
*/
public Message[] getPopMessages(String user, String password) throws MessagingException {
Properties props = new Properties();
props.setProperty("mail.imapStore.protocol", "pop3"); // 使用pop3协议
props.setProperty("mail.pop3.port", "110"); // 端口
props.setProperty("mail.pop3.host", RECEIVE_POP_HOST); // pop3服务器
Session session = Session.getInstance(props);
pop3Store = (POP3Store) session.getStore("pop3");
pop3Store.connect(RECEIVE_POP_HOST, RECEIVE_POP_PORT, user, password);
// 获得收件箱
pop3Folder = (POP3Folder) pop3Store.getFolder("INBOX");
/* Folder.READ_ONLY:只读权限
* Folder.READ_WRITE:可读可写(可以修改邮件的状态)
*/
pop3Folder.open(Folder.READ_WRITE); //打开收件箱
// 获取前一天的邮件信息
SearchTerm endTerm = new SentDateTerm(ComparisonTerm.LE, new Date(System.currentTimeMillis()));
SearchTerm startTerm = new SentDateTerm(ComparisonTerm.GE, new Date(System.currentTimeMillis() - time * 60 * 1000L));
SearchTerm searchTerm = new AndTerm(startTerm, endTerm);
//获取附件小于20M的邮件
int mailSize = 1024 * 1024 * 20;
SearchTerm intComparisonTerm = new SizeTerm(IntegerComparisonTerm.LT, mailSize);
Message[] messages = pop3Folder.search(intComparisonTerm);
// 得到收件箱中的所有邮件,并解析
return pop3Folder.search(searchTerm, messages);
}
/**
* @param
* @param msg
* @return java.lang.String
* @author FeianLing
* @date 2019/8/20
* @desc 获取发送地址
*/
public String getFrom(Message msg) throws MessagingException {
String from = "";
InternetAddress[] addresses = (InternetAddress[]) msg.getFrom();
if (null == addresses || addresses.length == 0) {
log.error("无法获取发送人地址信息!");
return from;
}
Address address = addresses[0];
log.info("发件人地址json:" + JSONObject.toJSONString(address));
String form = ((InternetAddress) address).getAddress();
return form;
}
/**
* 关闭folder和store资源
*
* @throws MessagingException
*/
public void close() throws MessagingException {
if (imapFolder != null) {
imapFolder.close(false);
}
if (imapStore != null) {
imapStore.close();
}
if (pop3Folder != null) {
pop3Folder.close(false);
}
if (pop3Store != null) {
pop3Store.close();
}
}
/**
* @param
* @param fileName
* @return boolean
* @author FeianLing
* @date 2019/8/20
* @desc 检查文件名称是否符合要求 FTK-88584316 FTK-申请号.pdf
*/
private boolean checkFileName(String fileName) {
return true;
}
/**
* @param
* @param part
* @return boolean
* @author FeianLing
* @date 2019/8/20
* @desc 判断邮件是否包含附件,如果没有包含附件,返回false 反之返回true
*/
public boolean isContainAttach(Part part) throws Exception {
boolean attachFlag = false;
// String contentType = part.getContentType();
if (part.isMimeType("multipart/*")) {
Multipart mp = (Multipart) part.getContent();
for (int i = 0; i < mp.getCount(); i++) {
BodyPart mPart = mp.getBodyPart(i);
String disposition = mPart.getDisposition();
if ((disposition != null)
&& ((disposition.equals(Part.ATTACHMENT)) || (disposition
.equals(Part.INLINE)))) {
attachFlag = true;
} else if (mPart.isMimeType("multipart/*")) {
attachFlag = isContainAttach((Part) mPart);
} else {
String conType = mPart.getContentType();
if (conType.toLowerCase().indexOf("application") != -1) {
attachFlag = true;
}
if (conType.toLowerCase().indexOf("name") != -1) {
attachFlag = true;
}
}
}
} else if (part.isMimeType("message/rfc822")) {
attachFlag = isContainAttach((Part) part.getContent());
}
return attachFlag;
}
/**
* @param
* @param msg
* @return boolean
* @author FeianLing
* @date 2019/8/20
* @desc 判断邮件是否是新的邮件
*/
private boolean isNew(Message msg) throws MessagingException {
boolean isNewFlag = false;
Flags flags = msg.getFlags();
Flags.Flag[] flagsArr = flags.getSystemFlags();
log.info("邮件状态:" + JSONObject.toJSONString(flagsArr));
for (Flags.Flag flag : flagsArr) {
if (flag == Flags.Flag.SEEN) {
isNewFlag = true;
log.info("当前邮件为未读状态!");
break;
}
}
return isNewFlag;
}
}
邮件附件实体类
import java.io.InputStream;
/**
* @author jiangyw
* @date 2019/1/10 21:14
*
* 邮件附件类
*/
public class MailAttachment {
private String name;
private InputStream inputStream;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
public MailAttachment(String name, InputStream inputStream) {
this.name = name;
this.inputStream = inputStream;
}
}