从TCP套接字开始——实现自己的JavaMail包(SMTP与POP3协议的手动实现)

我要讲啥?没什么好讲的,直接上代码!

Base64加密使用了Apache的开源包,使用时需导入commons-codec-1.11.jar包

另外,要说一下的就是国内的邮件服务器很多并没有用25端口和110端口接收和发送邮件,一般SMTP端口为465或587,而POP3端口为995,还有,现在的邮箱一般采用SSL加密,必须用SSL套接字建立连接,还有就是,第三方登陆邮箱用的是授权码而不是密码,其中SMTP是经过Base64编码后的授权码,POP3则直接是授权码......,借用代码记得删除package标记,另外还请保留署名,我可是有版权的!谢谢!好了,大概就这么多......

哦对了,先贴几个基础知识贴:

电子邮件收发原理和实现(POP3, SMTP) [整理]

邮件实现详解(一)------邮件发送的基本过程与概念

邮件实现详解(二)------手工体验smtp和pop3协议

邮件实现详解(三)------邮件的组织结构

用协议分析工具学习TCP/IP

图解SSL/TSL协议

package com.example;

import java.io.BufferedReader;
import java.io.OutputStream;
import java.net.Socket;

public class TransportModel {
	// 换行符
	protected final static String CRLF = "\r\n";
	// 用户名
	protected String Username = null;
	// 密码:授权码
	protected String Password = null;
	// iSocket套接字
	protected Socket iSocket = null;
	// 输入流
	protected BufferedReader bufferedReader = null;
	// 输出流
	protected OutputStream outputStream = null;
	// 是否已登陆
	protected boolean isConnected = false;

	public String getUsername() {
		return Username;
	}

	public void setUsername(String username) {
		Username = username;
	}

	public String getPassword() {
		return Password;
	}

	public void setPassword(String password) {
		Password = password;
	}
}

package com.example;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.net.ssl.SSLSocketFactory;;

/**
 * 
 * @author KING-ERIC
 * 
 */
public class POP3Recv extends TransportModel {

	// 邮件服务器域名地址
	private String POP3Host = null;
	// 邮件服务器端口,正常是110,腾讯SSL加密是995
	private int POP3Port;

	// 私有构造函数
	private POP3Recv() {

	}

	// 静态内部类,在该内部类中创建单例对象,再将该单例对象通过getInstance()方法返回给外部使用
	private static class InternalClass {
		private final static POP3Recv POP3Recv = new POP3Recv();
	}

	// 公有静态成员方法,返回唯一实例
	public static synchronized POP3Recv getPOP3Recv() {
		return InternalClass.POP3Recv;
	}

	// 公有静态成员方法,返回唯一实例
	public static synchronized POP3Recv getPOP3Recv(String Host, int Port) {
		InternalClass.POP3Recv.POP3Host = Host;
		InternalClass.POP3Recv.POP3Port = Port;
		return InternalClass.POP3Recv;
	}

	public String getPOP3Host() {
		return POP3Host;
	}

	public void setPOP3Host(String pOP3Host) {
		POP3Host = pOP3Host;
	}

	public int getPOP3Port() {
		return POP3Port;
	}

	public void setPOP3Port(int pOP3Port) {
		POP3Port = pOP3Port;
	}

	public String getUsername() {
		return Username;
	}

	public void setUsername(String username) {
		Username = username;
	}

	public String getPassword() {
		return Password;
	}

	public void setPassword(String password) {
		Password = password;
	}

	public synchronized boolean Login() {
		if (POP3Host == null || POP3Port == 0 || Username == null || Password == null) {
			try {
				throw new Exception("数据未初始化...");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return isConnected;
			}
		}
		if (!isConnected) {
			try {
				if (POP3Port == 110)
					iSocket = new Socket(POP3Host, POP3Port);
				else
					iSocket = SSLSocketFactory.getDefault().createSocket(POP3Host, POP3Port);
				outputStream = iSocket.getOutputStream();
				bufferedReader = new BufferedReader(new InputStreamReader(iSocket.getInputStream()));

				GetResponse();

				System.out.println("<------- 登陆 ------->");
				Send("USER " + Username + CRLF);
				GetResponse();
				Send("PASS " + Password + CRLF);
				GetResponse();

			} catch (UnknownHostException e) {
				e.printStackTrace();
				return isConnected;
			} catch (IOException e) {
				e.printStackTrace();
				return isConnected;
			} catch (Exception e) {
				e.printStackTrace();
				return isConnected;
			}
			isConnected = true;
		}
		return isConnected;
	}

	public synchronized String getState() {
		if (isConnected) {
			try {
				System.out.println("<------- 查询 ------->");
				Send("STAT " + CRLF);
			} catch (Exception e) {
				e.printStackTrace();
			}
			return GetResponse();
		}
		return null;
	}

	private void Send(String Command) {
		try {
			outputStream.write(Command.getBytes());
			// flush冲一下
			outputStream.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.print("S: " + Command);
	}

	private String GetResponse() {
		String aString = null;
		try {
			aString = bufferedReader.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("R: " + aString);
		return aString;
	}

	private String GetResponses() {
		String aString = null;
		StringBuffer aStringBuffer = new StringBuffer();
		try {
			/* LIST和RETR命令的应答虽然有多行,但都用一句"."作为结束,可据此取应答信息 */
			for (aString = bufferedReader.readLine(); (!aString.equals(".")); aString = bufferedReader.readLine()) {
				aStringBuffer.append(aString + "\n");
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(aStringBuffer.toString());
		return aStringBuffer.toString();
	}

	public synchronized String getList() {
		if (isConnected) {
			Query("LIST ");
			return GetResponses();
		}
		return null;
	}

	public synchronized String getContent(String Message) {
		if (isConnected) {
			Query("RETR " + Message);
			return GetResponses();
		}
		return null;
	}

	public synchronized String getUIDL(String Message) {
		if (isConnected) {
			Query("UIDL " + Message);
			return GetResponse();
		}
		return null;
	}

	private void Query(String Message) {
		try {
			System.out.println("<------- 查询 ------->");
			Send(Message + CRLF);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public synchronized String Delete(String Message) {
		if (isConnected) {
			System.out.println("<------- 删除 ------->");
			Send("DELE " + Message + CRLF);
			return GetResponse();
		}
		return null;
	}

	public synchronized String Reset() {
		if (isConnected) {
			System.out.println("<------- 重置 ------->");
			Send("RSET " + CRLF);
			return GetResponse();
		}
		return null;
	}

	public synchronized boolean Quit() {
		System.out.println("<------- 退出 ------->");
		Send("QUIT " + CRLF);
		isConnected = false;
		POP3Host = null;
		POP3Port = 0;
		Username = null;
		Password = null;
		if (bufferedReader != null) {
			try {
				bufferedReader.close();
			} catch (IOException e) {
			}
		}
		if (outputStream != null) {
			try {
				outputStream.close();
			} catch (IOException e) {
			}
		}
		if (iSocket != null) {
			try {
				iSocket.close();
			} catch (IOException e) {
			}
		}
		return isConnected;
	}

	public static synchronized boolean SaveFile(byte[] Data, String Path, String FileName) {
		File SaveFile = new File(Path, FileName);
		try {
			SaveFile.createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
		}
		FileOutputStream iFileOutputStream = null;
		try {
			iFileOutputStream = new FileOutputStream(SaveFile);
			iFileOutputStream.write(Data);
			iFileOutputStream.flush();
			return true;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		} finally {
			if (iFileOutputStream != null) {
				try {
					iFileOutputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	// 测试Main函数
	public static void main(String[] args) {
		POP3Recv iPOP3Recv = ConnectFactory.BulidPOP3Recv("[email protected]", "??想我用授权码?没门");
		iPOP3Recv.Login();
		iPOP3Recv.getList();
		iPOP3Recv.getState();
		iPOP3Recv.getUIDL("1");
		iPOP3Recv.getContent("1");
		iPOP3Recv.Delete("1");
		iPOP3Recv.Quit();
	}
}


package com.example;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Calendar;

import javax.net.ssl.SSLSocketFactory;

import org.apache.commons.codec.binary.Base64;

/**
 * 
 * @author KING-ERIC
 * 
 */
public class SmtpSend extends TransportModel {
	// 邮件服务器域名地址
	private String SmtpHost = null;// "smtp.qq.com"
	// 邮件服务器端口,正常是25,腾讯是587
	private int SmtpPort;
	// 主题
	private String Subject = null;
	// 发件人地址
	private String EmailAddr = null;// [email protected]
	// 收件人地址
	private String[] Receivers = null;// "[email protected]"
	// 内容
	private String Content = null;

	// 私有构造函数
	private SmtpSend() {

	}

	// 静态内部类,在该内部类中创建单例对象,再将该单例对象通过getInstance()方法返回给外部使用
	private static class InternalClass {
		private final static SmtpSend smtpSend = new SmtpSend();
	}

	// 公有静态成员方法,返回唯一实例
	public static synchronized SmtpSend getSmtpSend() {
		return InternalClass.smtpSend;
	}

	// 公有静态成员方法,返回唯一实例
	public static synchronized SmtpSend getSmtpSend(String Host, int Port) {
		InternalClass.smtpSend.SmtpHost = Host;
		InternalClass.smtpSend.SmtpPort = Port;
		return InternalClass.smtpSend;
	}

	public String getSmtpHost() {
		return SmtpHost;
	}

	public void setSmtpHost(String smtpHost) {
		SmtpHost = smtpHost;
	}

	public int getSmtpPort() {
		return SmtpPort;
	}

	public void setSmtpPort(int smtpPort) {
		SmtpPort = smtpPort;
	}

	public String getSubject() {
		return Subject;
	}

	public void setSubject(String subject) {
		Subject = subject;
	}

	public String getEmailAddr() {
		return EmailAddr;
	}

	public void setEmailAddr(String emailAddr) {
		EmailAddr = emailAddr;
	}

	public String[] getReceivers() {
		return Receivers;
	}

	public void setReceivers(String... receivers) {
		Receivers = receivers;
	}

	public String getContent() {
		return Content;
	}

	public void setContent(String content) {
		Content = content;
	}

	public synchronized boolean Login() {
		if (SmtpHost == null || SmtpPort == 0 || Username == null || Password == null) {
			try {
				throw new Exception("数据未初始化...");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return isConnected;
			}
		}
		if (!isConnected) {
			try {
				if (SmtpPort == 25) {
					iSocket = new Socket(SmtpHost, SmtpPort);
				} else
					iSocket = SSLSocketFactory.getDefault().createSocket(SmtpHost, SmtpPort);
				bufferedReader = new BufferedReader(new InputStreamReader(iSocket.getInputStream()));
				outputStream = iSocket.getOutputStream();

				isOK();

				// HELO - 打开(确认发送)
				System.out.println("<------- HELLO ------->");
				Send("HELO " + SmtpHost + CRLF);

				// STARTTLS
				System.out.println("<------- STARTTLS ------->");
				Send("STARTTLS " + SmtpHost + CRLF);

				// 账户验证
				System.out.println("<------- 请求登陆 ------->");
				Send("AUTH LOGIN " + CRLF);

				System.out.println("<------- 用户名 ------->");
				Send(Base64.encodeBase64String(Username.getBytes()) + CRLF);

				System.out.println("<------- 登录授权码 ------->");
				Send(Base64.encodeBase64String(Password.getBytes()) + CRLF);

			} catch (UnknownHostException e) {
				e.printStackTrace();
				return isConnected;
			} catch (IOException e) {
				e.printStackTrace();
				return isConnected;
			} catch (Exception e) {
				e.printStackTrace();
				return isConnected;
			}
			isConnected = true;
		}
		return isConnected;
	}

	// 邮件发送方法
	public synchronized boolean SendMail() {
		boolean Reasult = false;
		if (!isConnected || Subject == null || EmailAddr == null || Receivers == null || Content == null) {
			try {
				throw new Exception("数据未初始化...");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return Reasult;
			}
		}
		try {
			// 设置发件人
			System.out.println("<------- 设置发件人 ------->");
			Send("MAIL FROM:<" + EmailAddr + ">" + CRLF);

			// 设置收件人
			System.out.println("<------- 设置收件人 ------->");
			for (String Receiver : Receivers) {
				Send("RCPT TO:<" + Receiver + ">" + CRLF);
			}

			// 请求发送数据
			System.out.println("<------- 请求发送信件 ------->");
			Send("DATA " + CRLF);

			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.append("From:<" + EmailAddr + ">" + CRLF);
			for (String Receiver : Receivers) {
				stringBuilder.append("To:<" + Receiver + ">" + CRLF);
			}
			stringBuilder.append("Subject:" + Subject + CRLF);
			stringBuilder.append("Date:" + Calendar.getInstance().getTime().toString() + CRLF);
			stringBuilder.append("Content-Type:text/plain;charset=\"GB2312\"" + CRLF);
			stringBuilder.append(CRLF);
			stringBuilder.append(Content);
			stringBuilder.append(CRLF + "." + CRLF);
			System.out.println("<------- 发送信件 ------->");
			Reasult = Send(stringBuilder.toString());

			System.out.println("=========================>");
			Subject = null;
			EmailAddr = null;
			for (int i = 0; i < Receivers.length; i++) {
				Receivers[i] = null;
			}
			Receivers = null;
			Content = null;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return Reasult;
	}

	private String GetResponse() {
		String aString = null;
		try {
			aString = bufferedReader.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("R: " + aString);
		return aString;
	}

	private boolean Send(String Command) {
		try {
			outputStream.write(Command.getBytes());
			// flush冲一下
			outputStream.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.print("S: " + Command);
		return isOK();
	}

	private boolean isOK() {
		String Response = null;
		try {
			Response = GetResponse();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (Response != null && (Response.startsWith("2") || Response.startsWith("3"))) {
			// 211 系统状态或系统帮助响应
			// 214 帮助信息
			// 220  服务就绪
			// 221  服务关闭传输信道
			// 250 要求的邮件操作完成
			// 251 用户非本地,将转发向
			// 354 开始邮件输入,以.结束
			return true;
		}
		try {
			throw new Exception("发送消息出错...");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// 421  服务未就绪,关闭传输信道(当必须关闭时,此应答可以作为对任何命令的响应)
		// 450 要求的邮件操作未完成,邮箱不可用(例如,邮箱忙)
		// 451 放弃要求的操作;处理过程中出错
		// 452 系统存储不足,要求的操作未执行
		// 500 格式错误,命令不可识别(此错误也包括命令行过长)
		// 501 参数格式错误
		// 502 命令不可实现
		// 503 错误的命令序列
		// 504 命令参数不可实现
		// 550 要求的邮件操作未完成,邮箱不可用(例如,邮箱未找到,或不可访问)Connection frequency limited
		// 551 用户非本地,请尝试
		// 552 过量的存储分配,要求的操作未执行
		// 553 邮箱名不可用,要求的操作未执行(例如邮箱格式错误)
		// 554 操作失败
		return false;
	}

	public synchronized boolean Quit() {
		System.out.println("<------- 退出 ------->");
		Send("QUIT " + CRLF);
		isConnected = false;
		SmtpHost = null;
		SmtpPort = 0;
		Username = null;
		Password = null;
		if (bufferedReader != null) {
			try {
				bufferedReader.close();
			} catch (IOException e) {
			}
		}
		if (outputStream != null) {
			try {
				outputStream.close();
			} catch (IOException e) {
			}
		}
		if (iSocket != null) {
			try {
				iSocket.close();
			} catch (IOException e) {
			}
		}
		return isConnected;
	}

	// 测试Main函数
	public static void main(String[] args) {
		SmtpSend smtpSend = ConnectFactory.BulidSmtpSend("[email protected]", "???搞我授权码");

		smtpSend.setEmailAddr("[email protected]");
		smtpSend.setReceivers("[email protected]", "[email protected]");
		smtpSend.setSubject("Just a Test");
		smtpSend.setContent("This email from command line. Cross the GFW, we can reach every corner in the world !");
		smtpSend.SendMail();

		smtpSend.setEmailAddr("[email protected]");
		smtpSend.setReceivers("[email protected]", "[email protected]");
		smtpSend.setSubject("Just a Test");
		smtpSend.setContent("This email from command line. Cross the GFW, we can reach every corner in the world !");
		smtpSend.SendMail();

		smtpSend.Quit();
	}
}


package com.example;

public class ConnectFactory {
	// 静态工厂方法
	public synchronized static SmtpSend BulidSmtpSend(String EmailAddre, String Password) {
		SmtpSend aSmtpSend = SmtpSend.getSmtpSend();
		String Host = "smtp." + EmailAddre.substring(EmailAddre.lastIndexOf("@") + 1);
		String Username = EmailAddre.substring(0, EmailAddre.lastIndexOf("@"));
		int Port = 25;
		if (Host.equalsIgnoreCase("smtp.qq.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.163.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.126.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.yeah.net")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.netease.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.aol.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.139.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.yahoo.com")) {
			Host = "smtp.mail.yahoo.com";
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.sina.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.aliyun.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.gmx.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.sohu.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.vip.qq.com")) {
			Port = 465;
			Host = "smtp.qq.com";
		} else if (Host.equalsIgnoreCase("smtp.belief.com.cn")) {
			Port = 465;
			Host = "smtp.qq.com";
		} else if (Host.equalsIgnoreCase("smtp.tom.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.263.net")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.x263.net")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.vip.sina.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.21cn.com")) {
			Port = 465;
		} else if (Host.equalsIgnoreCase("smtp.china.com")) {
			Port = 465;
		}
		aSmtpSend.setSmtpHost(Host);
		aSmtpSend.setSmtpPort(Port);
		aSmtpSend.setUsername(Username);
		aSmtpSend.setPassword(Password);
		aSmtpSend.Login();
		return aSmtpSend;
	}

	// 静态工厂方法
	public synchronized static POP3Recv BulidPOP3Recv(String EmailAddre, String Password) {
		POP3Recv aPOP3Recv = POP3Recv.getPOP3Recv();
		String Host = "pop." + EmailAddre.substring(EmailAddre.lastIndexOf("@") + 1);
		String Username = EmailAddre.substring(0, EmailAddre.lastIndexOf("@"));
		int Port = 110;
		if (Host.equalsIgnoreCase("pop.qq.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.163.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.126.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.yeah.net")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.netease.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.aol.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.139.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.yahoo.com")) {
			Host = "pop.mail.yahoo.com";
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.sina.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.aliyun.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.gmx.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.sohu.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.vip.qq.com")) {
			Port = 995;
			Host = "pop.qq.com";
		} else if (Host.equalsIgnoreCase("pop.belief.com.cn")) {
			Port = 995;
			Host = "pop.qq.com";
		} else if (Host.equalsIgnoreCase("pop.tom.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.263.net")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.x263.net")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.vip.sina.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.21cn.com")) {
			Port = 995;
		} else if (Host.equalsIgnoreCase("pop.china.com")) {
			Port = 995;
		}
		aPOP3Recv.setPOP3Host(Host);
		aPOP3Recv.setPOP3Port(Port);
		aPOP3Recv.setUsername(Username);
		aPOP3Recv.setPassword(Password);
		aPOP3Recv.Login();
		return aPOP3Recv;
	}
}



你可能感兴趣的:(SMTP,POP3,JavaMail,Java,SSL)