我查看了参考文档,Spring 似乎对发送邮件有很好的支持。但是,我需要登录到一个邮件帐户,阅读邮件并下载任何附件。Spring 邮件 API 是否支持下载邮件附件?
我知道您可以使用 Java Mail API 来做到这一点,但过去我发现使用它非常冗长且令人不快。
编辑:我收到了一些回复,这些回复指向描述如何发送带有附件的邮件的教程,但我要问的是如何从收到的邮件中读取附件。
干杯,唐
我查看了参考文档,Spring 似乎对发送邮件有很好的支持。但是,我需要登录到一个邮件帐户,阅读邮件并下载任何附件。Spring 邮件 API 是否支持下载邮件附件?
我知道您可以使用 Java Mail API 来做到这一点,但过去我发现使用它非常冗长且令人不快。
编辑:我收到了一些回复,这些回复指向描述如何发送带有附件的邮件的教程,但我要问的是如何从收到的邮件中读取附件。
干杯,唐
这是我用于下载电子邮件的类(带有附件处理)。您必须浏览一下它正在做的一些事情(比如忽略日志记录类和数据库写入)。为了便于阅读,我还重新命名了一些包。
总体思路是将所有附件保存为文件系统中的单个文件,并且将每封电子邮件保存为数据库中的一条记录,其中包含一组指向所有附件文件路径的子记录。
专注于 doEMailDownload 方法。
/**
* Copyright (c) 2008 Steven M. Cherry
* All rights reserved.
*/
package utils.scheduled;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.sql.Timestamp;
import java.util.Properties;
import java.util.Vector;
import javax.mail.Address;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeBodyPart;
import glob.ActionLogicImplementation;
import glob.IOConn;
import glob.log.Log;
import logic.utils.sql.Settings;
import logic.utils.sqldo.EMail;
import logic.utils.sqldo.EMailAttach;
/**
* This will connect to our incoming e-mail server and download any e-mails
* that are found on the server. The e-mails will be stored for further processing
* in our internal database. Attachments will be written out to separate files
* and then referred to by the database entries. This is intended to be run by
* the scheduler every minute or so.
*
* @author Steven M. Cherry
*/
public class DownloadEMail implements ActionLogicImplementation {
protected String receiving_host;
protected String receiving_user;
protected String receiving_pass;
protected String receiving_protocol;
protected boolean receiving_secure;
protected String receiving_attachments;
/** This will run our logic */
public void ExecuteRequest(IOConn ioc) throws Exception {
Log.Trace("Enter");
Log.Debug("Executing DownloadEMail");
ioc.initializeResponseDocument("DownloadEMail");
// pick up our configuration from the server:
receiving_host = Settings.getValue(ioc, "server.email.receiving.host");
receiving_user = Settings.getValue(ioc, "server.email.receiving.username");
receiving_pass = Settings.getValue(ioc, "server.email.receiving.password");
receiving_protocol = Settings.getValue(ioc, "server.email.receiving.protocol");
String tmp_secure = Settings.getValue(ioc, "server.email.receiving.secure");
receiving_attachments = Settings.getValue(ioc, "server.email.receiving.attachments");
// sanity check on the parameters:
if(receiving_host == null || receiving_host.length() == 0){
ioc.SendReturn();
ioc.Close();
Log.Trace("Exit");
return; // no host defined.
}
if(receiving_user == null || receiving_user.length() == 0){
ioc.SendReturn();
ioc.Close();
Log.Trace("Exit");
return; // no user defined.
}
if(receiving_pass == null || receiving_pass.length() == 0){
ioc.SendReturn();
ioc.Close();
Log.Trace("Exit");
return; // no pass defined.
}
if(receiving_protocol == null || receiving_protocol.length() == 0){
Log.Debug("EMail receiving protocol not defined, defaulting to POP");
receiving_protocol = "POP";
}
if(tmp_secure == null ||
tmp_secure.length() == 0 ||
tmp_secure.compareToIgnoreCase("false") == 0 ||
tmp_secure.compareToIgnoreCase("no") == 0
){
receiving_secure = false;
} else {
receiving_secure = true;
}
if(receiving_attachments == null || receiving_attachments.length() == 0){
Log.Debug("EMail receiving attachments not defined, defaulting to ./email/attachments/");
receiving_attachments = "./email/attachments/";
}
// now do the real work.
doEMailDownload(ioc);
ioc.SendReturn();
ioc.Close();
Log.Trace("Exit");
}
protected void doEMailDownload(IOConn ioc) throws Exception {
// Create empty properties
Properties props = new Properties();
// Get the session
Session session = Session.getInstance(props, null);
// Get the store
Store store = session.getStore(receiving_protocol);
store.connect(receiving_host, receiving_user, receiving_pass);
// Get folder
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);
try {
// Get directory listing
Message messages[] = folder.getMessages();
for (int i=0; i < messages.length; i++) {
// get the details of the message:
EMail email = new EMail();
email.fromaddr = messages[i].getFrom()[0].toString();
Address[] to = messages[i].getRecipients(Message.RecipientType.TO);
email.toaddr = "";
for(int j = 0; j < to.length; j++){
email.toaddr += to[j].toString() + "; ";
}
Address[] cc;
try {
cc = messages[i].getRecipients(Message.RecipientType.CC);
} catch (Exception e){
Log.Warn("Exception retrieving CC addrs: %s", e.getLocalizedMessage());
cc = null;
}
email.cc = "";
if(cc != null){
for(int j = 0; j < cc.length; j++){
email.cc += cc[j].toString() + "; ";
}
}
email.subject = messages[i].getSubject();
if(messages[i].getReceivedDate() != null){
email.received_when = new Timestamp(messages[i].getReceivedDate().getTime());
} else {
email.received_when = new Timestamp( (new java.util.Date()).getTime());
}
email.body = "";
Vector<EMailAttach> vema = new Vector<EMailAttach>();
Object content = messages[i].getContent();
if(content instanceof java.lang.String){
email.body = (String)content;
} else if(content instanceof Multipart){
Multipart mp = (Multipart)content;
for (int j=0; j < mp.getCount(); j++) {
Part part = mp.getBodyPart(j);
String disposition = part.getDisposition();
if (disposition == null) {
// Check if plain
MimeBodyPart mbp = (MimeBodyPart)part;
if (mbp.isMimeType("text/plain")) {
Log.Debug("Mime type is plain");
email.body += (String)mbp.getContent();
} else {
Log.Debug("Mime type is not plain");
// Special non-attachment cases here of
// image/gif, text/html, ...
EMailAttach ema = new EMailAttach();
ema.name = decodeName(part.getFileName());
File savedir = new File(receiving_attachments);
savedir.mkdirs();
File savefile = File.createTempFile("emailattach", ".atch", savedir );
ema.path = savefile.getAbsolutePath();
ema.size = part.getSize();
vema.add(ema);
ema.size = saveFile(savefile, part);
}
} else if ((disposition != null) &&
(disposition.equals(Part.ATTACHMENT) || disposition.equals(Part.INLINE) )
){
// Check if plain
MimeBodyPart mbp = (MimeBodyPart)part;
if (mbp.isMimeType("text/plain")) {
Log.Debug("Mime type is plain");
email.body += (String)mbp.getContent();
} else {
Log.Debug("Save file (%s)", part.getFileName() );
EMailAttach ema = new EMailAttach();
ema.name = decodeName(part.getFileName());
File savedir = new File(receiving_attachments);
savedir.mkdirs();
File savefile = File.createTempFile("emailattach", ".atch", savedir );
ema.path = savefile.getAbsolutePath();
ema.size = part.getSize();
vema.add(ema);
ema.size = saveFile( savefile, part);
}
}
}
}
// Insert everything into the database:
logic.utils.sql.EMail.insertEMail(ioc, email);
for(int j = 0; j < vema.size(); j++){
vema.get(j).emailid = email.id;
logic.utils.sql.EMail.insertEMailAttach(ioc, vema.get(j) );
}
// commit this message and all of it's attachments
ioc.getDBConnection().commit();
// Finally delete the message from the server.
messages[i].setFlag(Flags.Flag.DELETED, true);
}
// Close connection
folder.close(true); // true tells the mail server to expunge deleted messages.
store.close();
} catch (Exception e){
folder.close(true); // true tells the mail server to expunge deleted messages.
store.close();
throw e;
}
}
protected int saveFile(File saveFile, Part part) throws Exception {
BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(saveFile) );
byte[] buff = new byte[2048];
InputStream is = part.getInputStream();
int ret = 0, count = 0;
while( (ret = is.read(buff)) > 0 ){
bos.write(buff, 0, ret);
count += ret;
}
bos.close();
is.close();
return count;
}
protected String decodeName( String name ) throws Exception {
if(name == null || name.length() == 0){
return "unknown";
}
String ret = java.net.URLDecoder.decode( name, "UTF-8" );
// also check for a few other things in the string:
ret = ret.replaceAll("=\\?utf-8\\?q\\?", "");
ret = ret.replaceAll("\\?=", "");
ret = ret.replaceAll("=20", " ");
return ret;
}
}
我对 Steven 的示例进行了一些处理,并删除了 Steven 特定的代码部分。如果有附件,我的代码将不会读取电子邮件的正文。这对我的情况很好,但你可能想为你的情况进一步完善它。
package utils;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.mail.Address;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeBodyPart;
public class IncomingMail {
public static List<Email> downloadPop3(String host, String user, String pass, String downloadDir) throws Exception {
List<Email> emails = new ArrayList<Email>();
// Create empty properties
Properties props = new Properties();
// Get the session
Session session = Session.getInstance(props, null);
// Get the store
Store store = session.getStore("pop3");
store.connect(host, user, pass);
// Get folder
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);
try {
// Get directory listing
Message messages[] = folder.getMessages();
for (int i = 0; i < messages.length; i++) {
Email email = new Email();
// from
email.from = messages[i].getFrom()[0].toString();
// to list
Address[] toArray = messages[i] .getRecipients(Message.RecipientType.TO);
for (Address to : toArray) { email.to.add(to.toString()); }
// cc list
Address[] ccArray = null;
try {
ccArray = messages[i] .getRecipients(Message.RecipientType.CC);
} catch (Exception e) { ccArray = null; }
if (ccArray != null) {
for (Address c : ccArray) {
email.cc.add(c.toString());
}
}
// subject
email.subject = messages[i].getSubject();
// received date
if (messages[i].getReceivedDate() != null) {
email.received = messages[i].getReceivedDate();
} else {
email.received = new Date();
}
// body and attachments
email.body = "";
Object content = messages[i].getContent();
if (content instanceof java.lang.String) {
email.body = (String) content;
} else if (content instanceof Multipart) {
Multipart mp = (Multipart) content;
for (int j = 0; j < mp.getCount(); j++) {
Part part = mp.getBodyPart(j);
String disposition = part.getDisposition();
if (disposition == null) {
MimeBodyPart mbp = (MimeBodyPart) part;
if (mbp.isMimeType("text/plain")) {
// Plain
email.body += (String) mbp.getContent();
}
} else if ((disposition != null) && (disposition.equals(Part.ATTACHMENT) || disposition .equals(Part.INLINE))) {
// Check if plain
MimeBodyPart mbp = (MimeBodyPart) part;
if (mbp.isMimeType("text/plain")) {
email.body += (String) mbp.getContent();
} else {
EmailAttachment attachment = new EmailAttachment();
attachment.name = decodeName(part.getFileName());
File savedir = new File(downloadDir);
savedir.mkdirs();
// File savefile = File.createTempFile( "emailattach", ".atch", savedir);
File savefile = new File(downloadDir,attachment.name);
attachment.path = savefile.getAbsolutePath();
attachment.size = saveFile(savefile, part);
email.attachments.add(attachment);
}
}
} // end of multipart for loop
} // end messages for loop
emails.add(email);
// Finally delete the message from the server.
messages[i].setFlag(Flags.Flag.DELETED, true);
}
// Close connection
folder.close(true); // true tells the mail server to expunge deleted messages
store.close();
} catch (Exception e) {
folder.close(true); // true tells the mail server to expunge deleted
store.close();
throw e;
}
return emails;
}
private static String decodeName(String name) throws Exception {
if (name == null || name.length() == 0) {
return "unknown";
}
String ret = java.net.URLDecoder.decode(name, "UTF-8");
// also check for a few other things in the string:
ret = ret.replaceAll("=\\?utf-8\\?q\\?", "");
ret = ret.replaceAll("\\?=", "");
ret = ret.replaceAll("=20", " ");
return ret;
}
private static int saveFile(File saveFile, Part part) throws Exception {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(saveFile));
byte[] buff = new byte[2048];
InputStream is = part.getInputStream();
int ret = 0, count = 0;
while ((ret = is.read(buff)) > 0) {
bos.write(buff, 0, ret);
count += ret;
}
bos.close();
is.close();
return count;
}
}
你还需要这两个辅助类
package utils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Email {
public Date received;
public String from;
public List<String> to = new ArrayList<String>();
public List<String> cc = new ArrayList<String>();
public String subject;
public String body;
public List<EmailAttachment> attachments = new ArrayList<EmailAttachment>();
}
和
package utils;
public class EmailAttachment {
public String name;
public String path;
public int size;
}
我用它来测试上面的类
package utils;
import java.util.List;
public class Test {
public static void main(String[] args) {
String host = "some host";
String user = "some user";
String pass = "some pass";
String downloadDir = "/Temp";
try {
List<Email> emails = IncomingMail.downloadPop3(host, user, pass, downloadDir);
for ( Email email : emails ) {
System.out.println(email.from);
System.out.println(email.subject);
System.out.println(email.body);
List<EmailAttachment> attachments = email.attachments;
for ( EmailAttachment attachment : attachments ) {
System.out.println(attachment.path+" "+attachment.name);
}
}
} catch (Exception e) { e.printStackTrace(); }
}
}
更多信息可以在http://java.sun.com/developer/onlineTraining/JavaMail/contents.html找到
这是一个错误:
else if ((disposition != null) && (disposition.equals(Part.ATTACHMENT)
|| disposition.equals(Part.INLINE) )
它应该是:
else if ((disposition.equalsIgnoreCase(Part.ATTACHMENT)
|| disposition.equalsIgnoreCase(Part.INLINE))
感谢@Stevenmcherry 的回答
我使用 Apache Commons Mail 来完成这个任务:
import java.util.List;
import javax.activation.DataSource;
import javax.mail.internet.MimeMessage;
import org.apache.commons.mail.util.MimeMessageParser;
public List<DataSource> getAttachmentList(MimeMessage message) throws Exception {
msgParser = new MimeMessageParser(message);
msgParser.parse();
return msgParser.getAttachmentList();
}
从DataSource
对象中,您可以检索InputStream
附件的(除了名称和类型)(请参阅 API:http ://docs.oracle.com/javase/6/docs/api/javax/activation/DataSource.html?is-external=真的)。
到目前为止,我只使用了 JavaMail API(出于我的目的,我对它们相当满意)。如果完整的 JavaMail 包对您来说太重,则可以使用底层传输引擎而无需包的顶层。您在 SMTP、POP3 和 IMAP 堆栈中的位置越低,您需要为自己做的准备就越多。
从好的方面来说,您还可以忽略应用程序不需要的部分。
import java.io.IOException;
import java.io.InputStream;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamSource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
@Controller
@RequestMapping("/sendEmail.do")
public class SendEmailAttachController {
@Autowired
private JavaMailSender mailSender;
@RequestMapping(method = RequestMethod.POST)
public String sendEmail(HttpServletRequest request,
final @RequestParam CommonsMultipartFile attachFile) {
// Input here
final String emailTo = request.getParameter("mailTo");
final String subject = request.getParameter("subject");
final String yourmailid = request.getParameter("yourmail");
final String message = request.getParameter("message");
// Logging
System.out.println("emailTo: " + emailTo);
System.out.println("subject: " + subject);
System.out.println("Your mail id is: "+yourmailid);
System.out.println("message: " + message);
System.out.println("attachFile: " + attachFile.getOriginalFilename());
mailSender.send(new MimeMessagePreparator() {
@Override
public void prepare(MimeMessage mimeMessage) throws Exception {
MimeMessageHelper messageHelper = new MimeMessageHelper(
mimeMessage, true, "UTF-8");
messageHelper.setTo(emailTo);
messageHelper.setSubject(subject);
messageHelper.setReplyTo(yourmailid);
messageHelper.setText(message);
// Attachment with mail
String attachName = attachFile.getOriginalFilename();
if (!attachFile.equals("")) {
messageHelper.addAttachment(attachName, new InputStreamSource() {
@Override
public InputStream getInputStream() throws IOException {
return attachFile.getInputStream();
}
});
}
}
});
return "Result";
}
}