JavaMail教程(三)-接收邮件

1.接收邮件

1.1使用POP3接收邮件

1.1.1输出收件箱信息

package org.ygy.demo;

import java.util.Properties;

import javax.mail.Folder;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;

public class ReceiveMail {
	public static final String HOST = "pop.126.com";//服务器地址
	public static final String PROTOCOL = "pop3";//协议
	public static final String PORT = "110";//pop默认端口为110
	public static final String USER = "[email protected]";//账户
	public static final String PASSWORD = "xxx";	//密码
	
	/**
	 * 输出收件箱的基本信息
	 */
	public void displayFolderInfo() {
		Properties props = new Properties();
		props.put("mail.pop3.host", ReceiveMail.HOST);//设置服务器地址
		props.put("mail.store.protocol" , ReceiveMail.PROTOCOL);//设置协议
		props.put("mail.pop3.port", "110");//设置端口
		
		Session session = Session.getDefaultInstance(props);
		Store store = null;
		Folder folder = null;
		try {
			store = session.getStore();
			store.connect(HOST , USER , PASSWORD);
			
			/*
			 * POP3 supports only a single folder named "INBOX".
			 * POP协议的话,这里只能是INBOX
			 */
			folder = store.getFolder("INBOX");
			folder.open(Folder.READ_ONLY);//以只读方式打开收件箱
			
			System.out.println("邮件总数:" + folder.getMessageCount());
			
			//由于POP3协议无法获知邮件的状态,所以getUnreadMessageCount()得到的是收件箱的邮件总数 
			System.out.println("未读邮件数:" + folder.getUnreadMessageCount());
			
			//由于POP3协议无法获知邮件的状态,所以下面得到的结果始终都是为0
			System.out.println("删除邮件数:" + folder.getDeletedMessageCount());
			System.out.println("新邮件数:" + folder.getNewMessageCount());
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		} finally {
			try {
				folder.close(false);
				store.close();
			} catch (MessagingException e) {
				e.printStackTrace();
			}
			
		}
		
	}
	
	public static void main(String[] args) {
		ReceiveMail receive = new ReceiveMail();
		receive.displayFolderInfo();
	}
}

结果显示如下图:

JavaMail教程(三)-接收邮件_第1张图片


这时,你可以通过浏览器登录“126邮箱”删除几封邮件,再运行测试一下,数据都是正确的。126邮箱默认都打开了POP/SMTP功能,可以设置的。

JavaMail教程(三)-接收邮件_第2张图片

注:126邮箱比较好用,之前使用QQ邮箱时,获取的”邮件总数“总是不对,结果显示只有16封,但是用浏览器登录QQ邮箱,可以看到一共有200多封,不知道还需要设置什么委屈。输出邮件内容之后,发现好像只有2013年的,疑问

1.1.2输出邮件信息

package org.ygy.demo;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

public class ReceiveMail {
	public static final String HOST = "pop.126.com";//服务器地址
	public static final String PROTOCOL = "pop3";//协议
	public static final String PORT = "110";//pop默认端口为110
	public static final String USER = "[email protected]";//账户
	public static final String PASSWORD = "xxx";	//密码
	public static final String DEFAULT_PATTERN = "yyyy年MM月dd日 E HH:mm";
	
	public static Session session = null;
	
	/**
	 * 输出收件箱的基本信息
	 */
	public void displayFolderInfo() {
		Session session = getSession();
		
		Store store = null;
		Folder folder = null;
		try {
			store = session.getStore();
			store.connect(HOST , USER , PASSWORD);
			
			/*
			 * POP3 supports only a single folder named "INBOX".
			 * POP协议的话,这里只能是INBOX
			 */
			folder = store.getFolder("INBOX");
			folder.open(Folder.READ_ONLY);//以只读方式打开收件箱
			
			System.out.println("邮件总数:" + folder.getMessageCount());
			
			//由于POP3协议无法获知邮件的状态,所以getUnreadMessageCount()得到的是收件箱的邮件总数 
			System.out.println("未读邮件数:" + folder.getUnreadMessageCount());
			
			//由于POP3协议无法获知邮件的状态,所以下面得到的结果始终都是为0
			System.out.println("删除邮件数:" + folder.getDeletedMessageCount());
			System.out.println("新邮件数:" + folder.getNewMessageCount());
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		} finally {
			try {
				folder.close(false);
				store.close();
			} catch (MessagingException e) {
				e.printStackTrace();
			}
			
		}
		
	}
	
	/**
	 * 获取Session
	 * @return
	 */
	public static Session getSession() {
		if(session == null) {
			Properties props = new Properties();
			props.put("mail.pop3.host", ReceiveMail.HOST);//设置服务器地址
			props.put("mail.store.protocol" , ReceiveMail.PROTOCOL);//设置协议
			props.put("mail.pop3.port", "110");//设置端口
			
			session = Session.getDefaultInstance(props);
		}
		
		return session;
	}
	
	/**
	 * 输出邮件的信息
	 */
	public void displayMessageInfo() {
		Session session = getSession();
		
		Store store = null;
		Folder folder = null;
		try {
			store = session.getStore();
			store.connect(HOST , USER , PASSWORD);
			
			folder = store.getFolder("INBOX");//POP协议的话,这里只能是INBOX
			folder.open(Folder.READ_ONLY);//以只读方式打开收件箱
			
			parseMessages(folder.getMessages());
		} catch (NoSuchProviderException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				folder.close(false);
				store.close();
			} catch (MessagingException e) {
				e.printStackTrace();
			}
			
		}
	}
	
	/**
	 * 解析邮件
	 * @param messages
	 * @throws MessagingException 
	 * @throws IOException 
	 */
	public void parseMessages(Message[] messages) throws MessagingException, IOException {
		if(messages.length < 1 || messages == null) {
			System.out.println("没有邮件");
		} else {
			for(int i = 0; i < messages.length; i++) {
				MimeMessage each = (MimeMessage) messages[i];
				System.out.println("------------------解析第" + each.getMessageNumber() + "封邮件-------------------- "); 
	            System.out.println("主题: " + getSubject(each)); 
	            System.out.println("发件人: " + getFrom(each)); 
	            System.out.println("收件人:" + getReceiveAddress(each, null)); 
	            System.out.println("发送时间:" + getSentDate(each, ReceiveMail.DEFAULT_PATTERN)); 
	            System.out.println("是否已读:" + isSeen(each)); 
	            System.out.println("邮件优先级:" + getPriority(each)); 
	            System.out.println("是否需要回执:" + isReplySign(each)); 
	            System.out.println("邮件大小:" + each.getSize() + "b"); 
	            boolean isContainerAttachment = isContainAttachment(each); 
	            System.out.println("是否包含附件:" + isContainerAttachment); 
	            if (isContainerAttachment) { 
	                saveAttachment(each, "F:\\mailtmp\\"+each.getSubject() + "_"); //保存附件 
	            }  
	            StringBuffer content = new StringBuffer(30); 
	            getMailTextContent(each, content); 
	            System.out.println("邮件正文:" + (content.length() > 100 ? content.substring(0,100) + "..." : content)); 
	            System.out.println("------------------第" + each.getMessageNumber() + "封邮件解析结束-------------------- "); 
	            System.out.println(); 
			}
		}
	}
	
	/**
	 * 获取邮件文本内容
	 * @param part 邮件体
	 * @param content 存储邮件文本内容的字符串
	 * @throws MessagingException
	 * @throws IOException
	 */
	private void getMailTextContent(Part part, StringBuffer content)
			throws MessagingException, IOException {
		// 如果是文本类型的附件,通过getContent方法可以取到文本内容,但这不是我们需要的结果,所以在这里要做判断
		boolean isContainTextAttach = part.getContentType().indexOf("name") > 0;
		if (part.isMimeType("text/*") && !isContainTextAttach) {
			content.append(part.getContent().toString());
		} else if (part.isMimeType("message/rfc822")) {
			getMailTextContent((Part) part.getContent(), content);
		} 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, content);
			}
		}
	}

	/**
	 * 保存附件
	 * @param part 邮件中多个组合体中的其中一个组合体 
	 * @param destDir 附件保存目录
	 * @throws UnsupportedEncodingException
	 * @throws MessagingException
	 * @throws IOException
	 */
	private void saveAttachment(Part part, String destDir) throws UnsupportedEncodingException, MessagingException, 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 disp = bodyPart.getDisposition(); 
                if (disp != null && (disp.equalsIgnoreCase(Part.ATTACHMENT) || disp.equalsIgnoreCase(Part.INLINE))) { 
                    InputStream is = bodyPart.getInputStream(); 
                    saveFile(is, destDir, decodeText(bodyPart.getFileName())); 
                } else if (bodyPart.isMimeType("multipart/*")) { 
                    saveAttachment(bodyPart,destDir); 
                } else { 
                    String contentType = bodyPart.getContentType(); 
                    if (contentType.indexOf("name") != -1 || contentType.indexOf("application") != -1) { 
                        saveFile(bodyPart.getInputStream(), destDir, decodeText(bodyPart.getFileName())); 
                    } 
                } 
            } 
        } else if (part.isMimeType("message/rfc822")) { 
            saveAttachment((Part) part.getContent(),destDir); 
        } 
	}

	/**
	 * 读取输入流中的数据保存至指定目录
	 * @param is 输入流 
	 * @param destDir 文件名
	 * @param fileName 文件存储目录
	 * @throws IOException
	 */
	private void saveFile(InputStream is, String destDir, String fileName) throws IOException {
		BufferedInputStream bis = new BufferedInputStream(is); 
        BufferedOutputStream bos = new BufferedOutputStream( 
                new FileOutputStream(new File(destDir + fileName))); 
        int len = -1;
        while ((len = bis.read()) != -1) {
            bos.write(len);
            bos.flush();
        } 
        bos.close(); 
        bis.close(); 
	}

	/**
	 * 文本解码
	 * @param encodeText 解码MimeUtility.encodeText(String text)方法编码后的文本
	 * @return 解码后的文本
	 * @throws UnsupportedEncodingException
	 */
	private String decodeText(String encodeText) throws UnsupportedEncodingException {
		if (encodeText == null || "".equals(encodeText)) { 
            return ""; 
        } else { 
            return MimeUtility.decodeText(encodeText); 
        } 
	}

	/**
	 * 判断邮件中是否包含附件
	 * @param part	邮件
	 * @return	邮件中存在附件返回true,不存在返回false
	 * @throws MessagingException
	 * @throws IOException
	 */
	private boolean isContainAttachment(Part part) throws MessagingException,
			IOException {
		boolean flag = false;
		
		if (part.isMimeType("multipart/*")) {
			MimeMultipart multipart = (MimeMultipart) part.getContent();
			int partCount = multipart.getCount();
			for (int i = 0; i < partCount; i++) {
				BodyPart bodyPart = multipart.getBodyPart(i);
				String disp = bodyPart.getDisposition();
				if (disp != null
						&& (disp.equalsIgnoreCase(Part.ATTACHMENT) || disp
								.equalsIgnoreCase(Part.INLINE))) {
					flag = true;
				} else if (bodyPart.isMimeType("multipart/*")) {
					flag = isContainAttachment(bodyPart);
				} else {
					String contentType = bodyPart.getContentType();
					if (contentType.indexOf("application") != -1) {
						flag = true;
					}

					if (contentType.indexOf("name") != -1) {
						flag = true;
					}
				}

				if (flag)
					break;
			}
		} else if (part.isMimeType("message/rfc822")) {
			flag = isContainAttachment((Part) part.getContent());
		}
		return flag;
	}

	/**
	 * 判断邮件是否需要回执
	 * @param msg	邮件
	 * @return 需要回执返回true,否则返回false
	 * @throws MessagingException
	 */
	private boolean isReplySign(MimeMessage msg) throws MessagingException {
		boolean replySign = false;
		String[] headers = msg.getHeader("Disposition-Notification-To");
		if (headers != null) {
			replySign = true;
		}
		
		return replySign;
	}

	/**
	 * 获得邮件的优先级
	 * @param msg 邮件
	 * @return	1(High):紧急  3:普通(Normal)  5:低(Low)
	 * @throws MessagingException
	 */
	private String getPriority(MimeMessage msg) throws MessagingException {
		String priority = "普通"; 
        String[] headers = msg.getHeader("X-Priority"); 
        if (headers != null) { 
            String headerPriority = headers[0]; 
            if (headerPriority.indexOf("1") != -1 || headerPriority.indexOf("High") != -1) {
                priority = "紧急"; 
            } else if (headerPriority.indexOf("5") != -1 || headerPriority.indexOf("Low") != -1) { 
                priority = "低"; 
            }else { 
                priority = "普通";
            }
        } 
        
        return priority; 
	}

	/**
	 * 判断邮件是否已读(使用POP3的话,这里应该都是未读)
	 * @param msg	邮件
	 * @return	已读-true;未读-false
	 * @throws MessagingException
	 */
	private boolean isSeen(MimeMessage msg) throws MessagingException {
		return msg.getFlags().contains(Flags.Flag.SEEN);
	}

	/**
	 * 获取邮件发送时间
	 * @param msg	邮件
	 * @param pattern	日期格式
	 * @return
	 * @throws MessagingException
	 */
	private String getSentDate(MimeMessage msg, String pattern)
			throws MessagingException {
		String sentDate = "";
		Date receivedDate = msg.getSentDate();
		if(receivedDate != null) {
			sentDate = new SimpleDateFormat(pattern).format(receivedDate);
		} else {
			sentDate = "没有邮件发送时间!";
		}
		
		return sentDate;
	}

	/**
	 * 根据收件人类型,获取邮件收件人、抄送和密送地址。如果收件人类型为空,则获得所有的收件人
	 * @param msg	邮件
	 * @param type 	收件人类型
	 * 				Message.RecipientType.TO  收件人
	 * 				Message.RecipientType.CC  抄送
	 * 				Message.RecipientType.BCC 密送
	 * @return
	 * @throws MessagingException
	 */
	private String getReceiveAddress(MimeMessage msg, Message.RecipientType type) throws MessagingException {
		StringBuffer receiveAddress = new StringBuffer(); 
        Address[] addresss = null; 
        if (type == null) { 
            addresss = msg.getAllRecipients(); 
        } else { 
            addresss = msg.getRecipients(type); 
        } 
         
		if (addresss == null || addresss.length < 1) {
			receiveAddress.append("没有收件人");
		} else {
			for (Address address : addresss) {
				InternetAddress internetAddress = (InternetAddress) address;
				receiveAddress.append(internetAddress.toUnicodeString()).append(",");
			}

			receiveAddress.deleteCharAt(receiveAddress.length() - 1); // 删除最后一个逗号
		}
         
        return receiveAddress.toString(); 
	}

	/**
	 * 获取发件人
	 * @param msg 邮件
	 * @return 姓名 <邮箱地址>
	 * @throws MessagingException
	 * @throws UnsupportedEncodingException
	 */
	private String getFrom(MimeMessage msg) throws MessagingException, UnsupportedEncodingException {
		Address[] froms = msg.getFrom();
		StringBuilder  from = new StringBuilder("");
		if (froms.length < 1) {
			from.append("没有收件人");
		} else {
			InternetAddress address = (InternetAddress) froms[0];
			from.append((address.getPersonal() == null)? "" : MimeUtility.decodeText(address.getPersonal()));
			from.append(" <").append(address.getAddress()).append(">");
		}

		return from.toString();
	}

	/**
	 * 获得邮件主题
	 * @param msg 邮件
	 * @return	解码后的邮件主题
	 * @throws UnsupportedEncodingException
	 * @throws MessagingException
	 */
	private String getSubject(MimeMessage msg) throws UnsupportedEncodingException, MessagingException {
		return  MimeUtility.decodeText(msg.getSubject());
	}

	public static void main(String[] args) {
		ReceiveMail receive = new ReceiveMail();
		receive.displayFolderInfo();
		receive.displayMessageInfo();
	}
}

邮件的附件部分没有仔细研究,代码是从下面的参考文章学习的。

2.参考文章

JavaMail学习笔记(一)、理解邮件传输协议(SMTP、POP3、IMAP、MIME)

JavaMail学习笔记(二)、JavaMail API简介和配置开发环境

JavaMail学习笔记(三)、使用SMTP协议发送电子邮件(全)

JavaMail学习笔记(四)、使用POP3协议接收并解析电子邮件(全)

JavaMail学习笔记(五)、使用IMAP协议接收并解析电子邮件

JavaMail学习笔记(六)、搜索邮件

你可能感兴趣的:(pop3,javamail,javamail,javamail,javamail,接收邮件)