使用JavaMail收发Internet邮件

JavaMail是JavaEE中的一个组件,用来开发邮件客户端程序(MUA)。JavaMail API本身是与具体的消息协议无关的,可以在运行程序之前设置实现具体协议的providers,例如在Sun的mail.jar中提供了一个缺省的文件javamail.default.providers,里面提供了三个协议(imap, smtp和pop3)的实现,其中smtp的provider类是com.sun.mail.smtp.SMTPTransport。如果用户需要开发NNTP协议的客户端程序,可以考虑其他的provider,例如GNU JavaMail。

JavaMail需要JavaSE中的 JavaBeans Activation Framework(JAF)才能运行,JAF位于package: javax.activation.*。这是因为接口Part/MimePart(实现类包括 Message,MimeMessage,BodyPart和MimeBodyPart)需要javax.activation.DataHandler来处理邮件的内容。


********Message的结构********

javax.mail.Message类是一个抽象类,针对Internet邮件,JavaMail中提供了一个具体类javax.mail.internet.MimeMessage。

一条邮件消息Message包含header和content两部分。

header包含Part接口中定义的通用头属性和实现类(比如Message,MimeMessage)中定义的头属性。例如MimeMessage的setHeader("X-Mailer","ljsspace")设置Internet邮件的X-Mailer头,MimeBodyPart的setHeader("Content-ID","a5c8x3f7i98")设置一个BodyPart的Content-ID,以便在其他Part的content中通过cid:a5c8x3f7i98引用该部分内容。

content可以是文本(包含text/plain或text/html),DataHandler或者Multipart/MimeMultipart。例如Part接口的setText(String)用来设置text/plain内容,setContent(String,"text/html")用来设置text/html内容,setContent(Multipart)用来设置Multipart内容,setDataHandler(DataHandler)设置DataHandler内容。另外,为了获取Message的内容,使用getDataHandler和getContent是具有同等效果。

上面提到的Multipart/MimeMultipart类是一个容器,它可以包含多个BodyPart/MimeBodyPart作为该容器中的组成部分,例如一封Internet邮件包含一个text/plain正文和一个附件,正文是一个MimeBodyPart,附件也是一个MimeBodyPart,合起来就是一个MimeMultipart,然后该MimeMultipart作为邮件MimeMessage的content。BodyPart也是Part接口的实现,即也是包含header和content两部分,显然BodyPart的content也可以是一个Multipart,甚至更多级的层次结构。


********接收和发送邮件********

接收邮件在JavaMail中使用的术语的是store,对应的Internet邮件协议有pop3和imap等(遵照JavaMail的习惯,协议名称一律用小写),每一个store中可以能有多有folders(一般情况下pop3中只支持INBOX这一个folder)。发送邮件在JavaMail中使用的术语是transport,对应的Internet邮件协议有smtp等。

在收发邮件之前需要建立一个Session对象,它是一个Factory类,可以生成收发邮件的Store和Transport对象。在smtp协议中,大部分MTA需要用邮件发送人地址的帐号通过认证才允许发邮件,以防open relay产生垃圾邮件,因此需要设置mail.smtp.auth为true,并在构建Session对象时指定一个Authenticator(也可以在transport.connect()时指定认证帐号)。

发送邮件可以用transport.send()或Transport.send(),后者是一个静态方法。如果使用静态方法,JavaMail会根据接收人的邮件地址构造transport对象来发送邮件,这是在后台自动完成的。另外Transport.send有两个重载方法,Transport.send(MimeMessage)根据message中的接收人列表发送邮件,Transport(MimeMessage,InternetAddress[])忽略message中的接收人列表,而直接按第二个参数的地址列表发送邮件,利用这个特点可以给邮件组(mailing list)发送邮件,参考以下代码实现。

接收邮件在JavaMail中使用一个lightweight的类MimeMessage,例如在调用inbox.getMessages()之后,并不是立即将有所有的邮件头和内容全部从store中读取过来,只有在需要的时候才读取。为此,JavaMail还提供了一个FetchProfile类,可以从store中获取所有邮件的部分头信息,而不必读取邮件内容。


********总结********

JavaMail是一个独立于具体协议的邮件或消息框架,除了上面介绍的核心内容之外,JavaMail还支持类似于Swing/AWT中的事件响应机制,而且还有一个专门的package(javax.mail.search)用来根据过滤条件从folder中检索邮件。使用JavaMail可以较轻松地构建一个跨平台的Internet邮件客户端程序,或者在企业环境下开发出邮件或消息子系统。

参考:JavaMail 1.4: http://www.oracle.com/technetwork/java/javamail/index.html

代码:

 

import java.io.File;
import java.io.InputStream;
import java.util.Date;
import java.util.Properties;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Authenticator;
import javax.mail.FetchProfile;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

/**
*
* JavaMail examples: send and fetch mail messages
*  
* Copyright (c) 2011 ljs (http://blog.csdn.net/ljsspace/)
* Licensed under GPL (http://www.opensource.org/licenses/gpl-license.php)
*
* @author ljs
* 2011-10-10
*
*/
public class JavaMail {
	/**
	 * send a message to a mailing list (e.g. [email protected]). The actual receivers (e.g. toAddr)
	 * are specified at the last moment when transport.send is called.
	 */
	public void sendMail(String host, final String user,
			final String password,
			String fromAddr,String toAddr,String subject,
			String msgText,File attachment,String filename) {
//		Transport transport = null;
		try {
			Properties props = System.getProperties(); //use system properties
			props.put("mail.debug", "true"); //or: session.setDebug(true)
			props.put("mail.transport.protocol", "smtp"); 			
			props.put("mail.smtp.host", host);
			props.put("mail.smtp.user", user);	
			
			//if SMTP authentication is required, we must set this property
			props.put("mail.smtp.auth", "true");  


			Authenticator auth = new Authenticator() {
				public PasswordAuthentication getPasswordAuthentication() {
					return new PasswordAuthentication(user, password);
				}
			};
			Session session = Session.getInstance(props, auth);//use authentication
			// session = Session.getDefaultInstance(props, null);
			
			MimeMessage msg = new MimeMessage(session); 
			
			msg.setFrom(new InternetAddress(fromAddr));
			//InternetAddress[] toAddress = {new InternetAddress(toAddr)};
			//msg.setRecipients(Message.RecipientType.TO, toAddress);
			String mailingListAddr = "[email protected]";
			msg.addRecipient(Message.RecipientType.TO, new InternetAddress(mailingListAddr,"Java List"));
			msg.setSubject(subject);
			
		
		    msg.setHeader("X-Mailer", "ljsspace-javamail");
		    msg.setSentDate(new Date());
		    
		    //create a multipart as the content
		    MimeMultipart multipart = new MimeMultipart();
		    
	    	MimeBodyPart mbp1 = new MimeBodyPart();
	    	mbp1.setText(msgText); 
	    	multipart.addBodyPart(mbp1);
		      
	    	//attachment
	    	DataSource fileDS = new FileDataSource(attachment);
			DataHandler fileDH = new DataHandler(fileDS);
			MimeBodyPart file_attachment = new MimeBodyPart();
			file_attachment.setDataHandler(fileDH);   
			file_attachment.setFileName(filename);				
			multipart.addBodyPart(file_attachment);
			
			//set content for the message; the content is a multipart object
			msg.setContent(multipart);
			//msg.saveChanges(); //unnecessary: Transport.send will call saveChanges
			
			//transport = session.getTransport(); 
			//transport.connect();
			//transport.send(msg);
			
			InternetAddress[] toAddress = {new InternetAddress(toAddr)};
			//Transport.send(msg); //only send to message's getRecipients()
			Transport.send(msg,toAddress); //ignore message's getRecipients()
		} catch (Exception e) {
			e.printStackTrace();
		} 
//		finally{	
//			try {
//				transport.close();
//			} catch (Exception ex) {
//				ex.printStackTrace();
//			}
//		}
	}

	/**
	 * Fetch messages from the INBOX store
	 * @param preview If true, display all messages' profiles; otherwise, display the contents of the first two new messages 
	 */
	public void fetchMail(boolean preview,String host, final String user,
			final String password) {
		Store store = null;
		Folder inbox = null;
		try {
			Properties props = System.getProperties();			
			props.put("mail.debug", "true");
			props.put("mail.store.protocol", "pop3"); //or store like imap
			props.put("mail.pop3.user", user); //no password!
			props.put("mail.pop3.host", host); 
			
			Authenticator auth = new Authenticator() {
				public PasswordAuthentication getPasswordAuthentication() {
					return new PasswordAuthentication(user, password);
				}
			};
			Session session = Session.getDefaultInstance(props, auth);
			
			// Get hold of a POP3 message store using session (a factory object)
			store = session.getStore();  //the same as session.getStore("pop3"). Since we've set mail.store.protocol property, we just call session.getStore().
			// store.connect(host, user, password); //use authenticator instead
			store.connect(); //connect using session's authenticator

			// inbox = store.getDefaultFolder(); //the root folder in the default namespace
			inbox = store.getFolder("INBOX"); //the only folder in POP3
			inbox.open(inbox.READ_WRITE);

			// Get the messages (a light-weight operation)
			Message[] msgs = inbox.getMessages();

			if(preview){
				FetchProfile fp = new FetchProfile();
				fp.add(FetchProfile.Item.ENVELOPE); //fetch subject, from, etc.
				fp.add("X-mailer"); //fetch x-mailer
				inbox.fetch(msgs, fp);	
				
				for (int i = 0; i < inbox.getMessageCount(); i++) {
					displayMessageProfile(msgs[i]);
				}
			}else{
				//read the first 2 messages only (from the newest to the oldest)
				for (int i = inbox.getMessageCount()-1; i>=0 && i > inbox.getMessageCount() - 3; i--) {
					processMessage(msgs[i]);
					//msgs[i].setFlag(Flags.Flag.DELETED, true);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (inbox != null)
					inbox.close(true); //expunge the deleted message
				if (store != null)
					store.close();
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	}

	// display a light-weight message's profile
	private void displayMessageProfile(Message message) {
		try {
			System.out.println(message.getFrom()[0] + "\t" + message.getSubject());
		} catch (MessagingException e) {			
			e.printStackTrace();
		}		
	}
	private void processMessage(Message message) {
		try {
			System.out.println("*******" + message.getSubject() + "*******");
			readPart(message);
		} catch (MessagingException e) {			
			e.printStackTrace();
		}	
	}
	
	private void readPart(Part p) {
		try {
			Object content = p.getContent();
			if(content instanceof String){
				System.out.println(content);
			}else if (content instanceof Multipart) {
				Multipart mp = (Multipart) content;
				int count = mp.getCount();
				for (int i = 0; i < count; i++) {
					Part bodyPart = mp.getBodyPart(i); //or check: boyPart.getDisposition()
					readPart(bodyPart); //recursion
				}
			}else if (content instanceof InputStream) {
				System.out.println("****found inputstream as a part's content****");
			}else{
				System.out.println("****unknown type****");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {		
		//test store: pop3
		String pop3host="pop.126.com";
		String pop3user="abc"; //test account
		String pop3pass="******";
		JavaMail mailer = new JavaMail();
		mailer.fetchMail(true,pop3host, pop3user, pop3pass);
		
		
		//test transport: smtp
		String smtphost="smtp.126.com";
		String smtpuser="abc"; //test account
		String smtppass="******";
		String fromAddr="[email protected]";
		String toAddr="[email protected]";		
		String subject="A Test Message sent via JavaMail";
		String msgText = "Please see the attachment for details.";
		File attachment = new File("/tmp/test.pdf");
		String filename = "test.pdf";
		mailer.sendMail(smtphost, smtpuser,smtppass,
				fromAddr,toAddr,subject,
				msgText,attachment,filename);
	}

}


你可能感兴趣的:(exception,String,session,user,internet,javamail)