忘记是从哪里看来的了。。。
网上一大堆
Java发送邮件有2大类
1. 用别人写的jar包来发送,比较简单安心,快速
2. 自己更具SMTP协议来发送邮件,比较烦,但是更好玩
---
1. 使用javax.mail来发送代码:
MailSenderInfo(发送邮件需要使用的基本信息)
package sendJavaMail; import java.util.Properties; /** * 发送邮件需要使用的基本信息 */ public class MailSenderInfo { // 发送邮件的服务器的IP和端口 private String mailServerHost; private String mailServerPort = "25"; // 邮件发送者的地址 private String fromAddress; // 邮件接收者的地址 private String toAddress; // 登陆邮件发送服务器的用户名和密码 private String userName; private String password; // 是否需要身份验证 private boolean validate = false; // 邮件主题 private String subject; // 邮件的文本内容 private String content; // 邮件附件的文件名 private String[] attachFileNames; /** * 获得邮件会话属性 */ public Properties getProperties() { Properties p = new Properties(); p.put("mail.smtp.host", this.mailServerHost); p.put("mail.smtp.port", this.mailServerPort); p.put("mail.smtp.auth", validate ? "true" : "false"); return p; } public String getMailServerHost() { return mailServerHost; } public void setMailServerHost(String mailServerHost) { this.mailServerHost = mailServerHost; } public String getMailServerPort() { return mailServerPort; } public void setMailServerPort(String mailServerPort) { this.mailServerPort = mailServerPort; } public boolean isValidate() { return validate; } public void setValidate(boolean validate) { this.validate = validate; } public String[] getAttachFileNames() { return attachFileNames; } public void setAttachFileNames(String[] fileNames) { this.attachFileNames = fileNames; } public String getFromAddress() { return fromAddress; } public void setFromAddress(String fromAddress) { this.fromAddress = fromAddress; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getToAddress() { return toAddress; } public void setToAddress(String toAddress) { this.toAddress = toAddress; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getContent() { return content; } public void setContent(String textContent) { this.content = textContent; } }
SimpleMailSender(简单邮件(不带附件的邮件)发送器)
package sendJavaMail; import java.io.UnsupportedEncodingException; import java.util.Date; import java.util.Properties; import javax.mail.Address; import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; /** * 简单邮件(不带附件的邮件)发送器 */ public class SimpleMailSender { /** * 以文本格式发送邮件 * * @param mailInfo * 待发送的邮件的信息 */ public boolean sendTextMail(MailSenderInfo mailInfo) { // 判断是否需要身份认证 MyAuthenticator authenticator = null; Properties pro = mailInfo.getProperties(); if (mailInfo.isValidate()) { // 如果需要身份认证,则创建一个密码验证器 authenticator = new MyAuthenticator(mailInfo.getUserName(), mailInfo.getPassword()); } // 根据邮件会话属性和密码验证器构造一个发送邮件的session Session sendMailSession = Session .getDefaultInstance(pro, authenticator); try { // 根据session创建一个邮件消息 Message mailMessage = new MimeMessage(sendMailSession); // 创建邮件发送者地址 Address from; try { // 设置自定义发件人昵称 String nick = javax.mail.internet.MimeUtility .encodeText("昵称wxsTest"); from = new InternetAddress(mailInfo.getFromAddress(), nick); } catch (UnsupportedEncodingException e) { from = new InternetAddress(mailInfo.getFromAddress()); } // 设置邮件消息的发送者 mailMessage.setFrom(from); // 创建邮件的接收者地址,并设置到邮件消息中 Address to = new InternetAddress(mailInfo.getToAddress()); // mailMessage.setRecipient(Message.RecipientType.TO, to); //单人 mailMessage.setRecipients(Message.RecipientType.TO, new Address[] { to, from }); // 多人 // cc设置抄送人 mailMessage.setRecipients(Message.RecipientType.CC, new Address[] { to }); // bcc设置暗抄送人 mailMessage.setRecipients(Message.RecipientType.BCC, new Address[] { from }); // 设置邮件消息的主题 mailMessage.setSubject(mailInfo.getSubject()); // 设置邮件消息发送的时间 mailMessage.setSentDate(new Date()); // 设置邮件消息的主要内容 String mailContent = mailInfo.getContent(); mailMessage.setText(mailContent); // 发送邮件 Transport.send(mailMessage); return true; } catch (MessagingException ex) { ex.printStackTrace(); } return false; } /** * 以HTML格式发送邮件 * * @param mailInfo * 待发送的邮件信息 */ public static boolean sendHtmlMail(MailSenderInfo mailInfo) { // 判断是否需要身份认证 MyAuthenticator authenticator = null; Properties pro = mailInfo.getProperties(); // 如果需要身份认证,则创建一个密码验证器 if (mailInfo.isValidate()) { authenticator = new MyAuthenticator(mailInfo.getUserName(), mailInfo.getPassword()); } // 根据邮件会话属性和密码验证器构造一个发送邮件的session Session sendMailSession = Session .getDefaultInstance(pro, authenticator); try { // 根据session创建一个邮件消息 Message mailMessage = new MimeMessage(sendMailSession); // 创建邮件发送者地址 Address from; try { // 设置自定义发件人昵称 String nick = javax.mail.internet.MimeUtility .encodeText("昵称wxsTest"); from = new InternetAddress(mailInfo.getFromAddress(), nick); } catch (UnsupportedEncodingException e) { from = new InternetAddress(mailInfo.getFromAddress()); } // 设置邮件消息的发送者 mailMessage.setFrom(from); // 创建邮件的接收者地址,并设置到邮件消息中 Address to = new InternetAddress(mailInfo.getToAddress()); // Message.RecipientType.TO属性表示接收者的类型为TO // mailMessage.setRecipient(Message.RecipientType.TO, to); //单人 mailMessage.setRecipients(Message.RecipientType.TO, new Address[] { to, from }); // 多人 // cc设置抄送人 mailMessage.setRecipients(Message.RecipientType.CC, new Address[] { to }); // bcc设置暗抄送人 mailMessage.setRecipients(Message.RecipientType.BCC, new Address[] { from }); // 设置邮件消息的主题 mailMessage.setSubject(mailInfo.getSubject()); // 设置邮件消息发送的时间 mailMessage.setSentDate(new Date()); // MiniMultipart类是一个容器类,包含MimeBodyPart类型的对象 Multipart mainPart = new MimeMultipart(); // 创建一个包含HTML内容的MimeBodyPart BodyPart html = new MimeBodyPart(); // 设置HTML内容 html.setContent(mailInfo.getContent(), "text/html; charset=utf-8"); mainPart.addBodyPart(html); // 将MiniMultipart对象设置为邮件内容 mailMessage.setContent(mainPart); // 发送邮件 Transport.send(mailMessage); return true; } catch (MessagingException ex) { ex.printStackTrace(); } return false; } }
MyAuthenticator(服务器认证)
package sendJavaMail; import javax.mail.*; public class MyAuthenticator extends Authenticator { String userName = null; String password = null; public MyAuthenticator() { } public MyAuthenticator(String username, String password) { this.userName = username; this.password = password; } protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(userName, password); } }
Main方法
public static void main(String[] args) { // 这个类主要是设置邮件 MailSenderInfo mailInfo = new MailSenderInfo(); mailInfo.setMailServerHost("smtp.server.com"); //smtp服务器地址 mailInfo.setMailServerPort("25"); //smtp服务器端口号,一般是25 mailInfo.setValidate(true); mailInfo.setUserName("username"); // 自己登录用户名 mailInfo.setPassword("password");// 自己登录密码 mailInfo.setFromAddress("my@gmail.com"); // /自己邮箱地址 mailInfo.setToAddress("you@gmail.com"); // 对方邮箱地址 mailInfo.setSubject("Title,タイトル、测试"); mailInfo.setContent("<font style='color:red;'><b>Test,テスト内容、测试内容</b></font>"); // 这个类主要来发送邮件 SimpleMailSender sms = new SimpleMailSender(); sms.sendTextMail(mailInfo);// 发送文体格式 sms.sendHtmlMail(mailInfo); // 发送html格式 }
2. 根据SMTP协议发送邮件
首先是SMTP协议简介:
http://blog.youkuaiyun.com/wasingmon/article/details/552448
SMTP 命令简介
什么是 SMTP
SMTP (Simple Mail Transfer Protocol) : 电子邮件从客户机传输到服务器或从某一个服务器传输到另一个服务器使用的传输协议。 SMTP 是请求/响应协议,命令和响应都是基于 ASCII 文本,并以 CR 和 LF 符结束。响应包括一个表示返回状态的三位数字代码。SMTP 在 TCP 协议 25 端口监听连接请求。
什么是 ESMTP
ESMTP (Extended SMTP),顾名思义,扩展 SMTP 就是对标准 SMTP 协议进行的扩展。它与 SMTP 服务的区别仅仅是,使用 SMTP 发信不需要验证用户帐户,而用 ESMTP 发信时,服务器会要求用户提供用户名和密码以便验证身份。验证之后的邮件发送过程与 SMTP 方式没有两样。
SMTP 命令包括:
HELO 向服务器标识用户身份。发送者能欺骗,说谎,但一般情况下服务器都能检测到。
EHLO 向服务器标识用户身份。发送者能欺骗,说谎,但一般情况下服务器都能检测到。
MAIL FROM 命令中指定的地址是发件人地址
RCPT TO 标识单个的邮件接收人;可有多个 RCPT TO;常在 MAIL 命令后面。
DATA 在单个或多个 RCPT 命令后,表示所有的邮件接收人已标识,并初始化数据传输,以 CRLF.CRLF 结束
VRFY 用于验证指定的用户/邮箱是否存在;由于安全方面的原因,服务器常禁止此命令
EXPN 验证给定的邮箱列表是否存在,扩充邮箱列表,也常被禁用
HELP 查询服务器支持什么命令
NOOP 无操作,服务器应响应 OK
RSET 重置会话,当前传输被取消
QUIT 结束会话
连接到 Postfix 使用 SMTP 命令发送邮件
例如:安装 Postfix 的邮件服务器IP是192.168.0.1 (蓝色字体内容由客户端输入,红色字体内容是服务返回的)
telnet 192.168.0.1 25 ------------------------------------------------- 使用 telnet 命令连接服务器 25 端口
helo test.com -----------------------------------------------------------向服务器标识用户身份发送 mail from 命令
ehlo test.com ----------------------------------------------------------- ESMTP 命令,发信需要认证。
auth login ----------------------------------------------------------------进行用户身份认证
334 VXNlcm5hbWU6
Y29zdGFAYW1heGl0Lm5ldA== ----------------------------------- BASE64 加密后的用户名
334 UGFzc3dvcmQ6
MTk4MjIxNA== -------------------------------------------------------- BASE64 加密后的密码
235 authentication successfully -------------------------------- 身份认证成功
(535 authentication failed --------------------------------- ------身份认证失败)
发到本系统中域名下的账户可跳过身份认证。
mail from: <test1@domain.com> ---------------------------- mail from 地址 test1@domain.com
250 ok ----------------------------------------------------- ----------命令执行成功
rcpt to: <test2@domain.com> -------------------------------- 递送给地址 test2@domain.com
250 ok ----------------------------------------------------- ----------命令执行成功
data ------------------------------------------------------- -----------数据传输初始化
354 End data with .----------------------------------------- -----开始传输数据
From: test1@domain.com
To: test2@domain.com
Date: Mon, 25 Oct 2004 14:24:27 +0800
Subject: test mail
Hi, test2
This is a test mail, you don't reply it.
.
------------------------------------------------------------ 数据内容,包括BASE64加密后的邮件内容, 以 CRLF.CRLF 结束数据传输
250 OK: queued as 2F6DE3929--------------------------------- 命令执行成功
quit ------------------------------------------------------- 结束会话
221 Bye
Connection closed by foreign host .------------------------- 断开连接
以上就是一个邮件发送的基本的命令。
再说一下邮件发送的基本过程:
如果你的邮件地址是a@host.com,而你要用这个邮箱发送一封邮件到to@tohost.com,你需要连接到服务器host.com上,当然这个连接可能需要认证,现在基本上都要验证,然后是发送邮件到服务器host.com上,关闭连接。在host.com上,你所发送的邮件进入发送队列中,轮到你要发送的邮件时,host.com主机再联系tohost.com,将邮件传输到服务器tohost.com上。
代码流程:
Main入口
1.set数据[发件人,发送人,用户名,密码,标题,内容,smtp服务地址,端口等]
2.socket建立连接[smtp服务地址,端口]
3.执行发送邮件命令:
3.1.通过socket建立BufferedReader,BufferedWriter
3.2.helo命令[判断服务器连接是否成功]
3.3.authLogin命令
3.3.1.发送命令:"AUTH LOGIN"
3.3.2.发送BASE64Encoder加密后 登录用户名
3.3.3.发送BASE64Encoder加密后 登录密码
3.4.mailfrom指定发件人邮箱
3.4.1.发送命令:"MAIL FROM:<" + mail + ">"
3.5.rcpt指定接受人邮箱
3.5.1.发送命令:"RCPT TO:<" + mail + ">"[发给多个人就多几次]
3.6.data传输数据
3.6.1.发送命令:"DATA"
3.6.2.发送命令:"From: "+xxx[昵称]
3.6.3.发送命令:"To: "+xxx[可以添加Cc:,Bcc:命令,但是地址必须在3.5.1中发送过RCPT TO:命令的; 多个的话,可以用"; "分割]
3.6.4.发送命令:"Subject: "+xxx
3.6.5.发送命令:邮件内容
3.6.6.句号加回车结束邮件内容输入
3.7.退出smtp服务器
3.7.1.发送命令:"QUIT"
代码:
MailMessage(一些基本信息的设置)
package sendSMTPMail; /** * 这个类其实就是一个基本的JavaBean, 用于完成一些基本信息的设置, 也可以不要这个东西 直接在程序中写明就可以, 不过这样条理较清楚一些, * 而且修改也方便一些. * */ public class MailMessage { private String from; private String to; private String datafrom; private String datato; private String subject; private String content; private String date; private String user; private String password; public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUser() { return user; } public void setUser(String user) { this.user = user; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getDatafrom() { return datafrom; } public void setDatafrom(String datafrom) { this.datafrom = datafrom; } public String getDatato() { return datato; } public void setDatato(String datato) { this.datato = datato; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getTo() { return to; } public void setTo(String to) { this.to = to; } }
SMTPClient(主要的功能)
package sendSMTPMail; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.Socket; import java.net.SocketException; import java.net.UnknownHostException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import java.util.StringTokenizer; import java.util.TimeZone; import sun.misc.BASE64Encoder; /** * * 主要的功能就在这里面完成了 * */ @SuppressWarnings("restriction") public class SMTPClient { private boolean debug = true; BASE64Encoder encode = new BASE64Encoder();// 用于加密后发送用户名和密码 public static void main(String[] args) throws UnknownHostException, IOException { MailMessage message = new MailMessage(); message.setFrom("my@gmail.com");// 发件人 message.setTo("you@gmail.com");// 收件人 String server = "smtp.com";// 邮件服务器 message.setSubject("test 测试 テスト");// 邮件主题 message.setContent("<b>test 测试 テスト</b>");// 邮件内容 message.setDatafrom("my@gmail.com");// 发件人,在邮件的发件人栏目中显示 message.setDatato("you@gmail.com");// 收件人,在邮件的收件人栏目中显示 message.setUser("username");// 登陆邮箱的用户名 message.setPassword("password");// 登陆邮箱的密码 SMTPClient smtp = new SMTPClient(server, 25); boolean flag; flag = smtp.sendMail(message, server); if (flag) { System.out.println("邮件发送成功!"); } else { System.out.println("邮件发送失败!"); } } private Socket socket; public SMTPClient(String server, int port) throws UnknownHostException, IOException { try { socket = new Socket(server, 587);// 一般是25 } catch (SocketException e) { System.out.println(e.getMessage()); } catch (Exception e) { e.printStackTrace(); } finally { System.out.println("已经建立连接!"); } } // 注册到邮件服务器 public void helo(String server, BufferedReader in, BufferedWriter out) throws IOException { int result; result = getResult(in); // 连接上邮件服务后,服务器给出220应答 if (result != 220) { throw new IOException("连接服务器失败"); } result = sendServer("HELO " + server, in, out); // HELO命令成功后返回250 if (result != 250) { throw new IOException("注册邮件服务器失败!"); } } private int sendServer(String str, BufferedReader in, BufferedWriter out) throws IOException { out.write(str); out.newLine(); out.flush(); if (debug) { System.out.println("已发送命令:" + str); } return getResult(in); } public int getResult(BufferedReader in) { String line = ""; try { line = in.readLine(); if (debug) { System.out.println("服务器返回状态:" + line); } } catch (Exception e) { e.printStackTrace(); } // 从服务器返回消息中读出状态码,将其转换成整数返回 StringTokenizer st = new StringTokenizer(line, " "); return Integer.parseInt(st.nextToken()); } public void authLogin(MailMessage message, BufferedReader in, BufferedWriter out) throws IOException { int result; result = sendServer("AUTH LOGIN", in, out); if (result != 334) { throw new IOException("用户验证失败!"); } result = sendServer(encode.encode(message.getUser().getBytes()), in, out); if (result != 334) { throw new IOException("用户名错误!"); } result = sendServer(encode.encode(message.getPassword().getBytes()), in, out); if (result != 235) { throw new IOException("验证失败!"); } } // 开始发送消息,邮件源地址 public void mailfrom(String source, BufferedReader in, BufferedWriter out) throws IOException { int result; result = sendServer("MAIL FROM:<" + source + ">", in, out); if (result != 250) { throw new IOException("指定源地址错误"); } } // 设置邮件收件人 public void rcpt(String touchman, BufferedReader in, BufferedWriter out) throws IOException { int result; result = sendServer("RCPT TO:<" + touchman + ">", in, out); result = sendServer("RCPT TO:<" + "to2@gmail.com" + ">", in, out); // 发送给多个收信人方法 result = sendServer("RCPT TO:<" + "to3@gmail.com" + ">", in, out); // 发送给多个收信人方法 result = sendServer("RCPT TO:<" + "to4@gmail.com" + ">", in, out); // 发送给多个收信人方法 if (result != 250) { throw new IOException("指定目的地址错误!"); } } // 邮件体 public void data(String from, String to, String subject, String content, BufferedReader in, BufferedWriter out) throws IOException { int result; result = sendServer("DATA", in, out); // 输入DATA回车后,若收到354应答后,继续输入邮件内容 if (result != 354) { throw new IOException("不能发送数据"); } out.write("Content-Type: text/html;charset=\"UTF-8\""); //可以是纯文本:text/plain out.newLine(); out.write("From: " + from);// 可以用email地址 // 中文有时会乱码,下面的方法在同域下可行,跨域后会有问题:"=?UTF-8?B?"+encode.encode(("昵称").getBytes())+"?=" out.newLine(); out.write("To: " + to+ "; to2@gmail.com"); // 设置收信栏显示内容,可以设置多个,但真正发送需要使用命令 RCPT TO: out.newLine(); out.write("Cc: " + "to3@gmail.com"); // CC out.newLine(); out.write("Bcc: " + "to4@gmail.com"); // BCC out.newLine(); out.write("Subject: " + subject); out.newLine(); TimeZone tz = TimeZone.getTimeZone( "GMT+01:00" ); Date now = new Date(); out.write("Date: " + formatSMTPDate( now, tz ) ); out.newLine(); out.newLine(); out.write(content); out.newLine(); // 句号加回车结束邮件内容输入 result = sendServer(".", in, out); System.out.println(result); if (result != 250) { throw new IOException("发送数据错误"); } } /* Tue, 16 Sep 1997 15:39:01 -0400 (EDT) */ public String formatSMTPDate(Date date, TimeZone tz) throws IllegalArgumentException { SimpleDateFormat dateFormat; Locale loc = Locale.US; dateFormat = new SimpleDateFormat("EEE", loc); dateFormat.setTimeZone(tz); String day = dateFormat.format(date); day = day.substring(0, 3); dateFormat = new SimpleDateFormat("MMM", loc); dateFormat.setTimeZone(tz); String month = dateFormat.format(date); month = month.substring(0, 3); dateFormat = new SimpleDateFormat("dd", loc); dateFormat.setTimeZone(tz); String dayNum = dateFormat.format(date); dateFormat = new SimpleDateFormat("yyyy HH:mm:ss", loc); dateFormat.setTimeZone(tz); String rest = dateFormat.format(date); String result = new String(day + ", " + dayNum + " " + month + " " + rest + " +0000"); return result; } // 退出 public void quit(BufferedReader in, BufferedWriter out) throws IOException { int result; result = sendServer("QUIT", in, out); if (result != 221) { throw new IOException("未能正确退出"); } } // 发送邮件主程序 public boolean sendMail(MailMessage message, String server) { try { BufferedReader in = new BufferedReader(new InputStreamReader( socket.getInputStream())); BufferedWriter out = new BufferedWriter(new OutputStreamWriter( socket.getOutputStream())); helo(server, in, out);// HELO命令 authLogin(message, in, out);// AUTH LOGIN命令 mailfrom(message.getFrom(), in, out);// MAIL FROM rcpt(message.getTo(), in, out);// RCPT data(message.getDatafrom(), message.getDatato(), message.getSubject(), message.getContent(), in, out);// DATA quit(in, out);// QUIT } catch (Exception e) { e.printStackTrace(); return false; } return true; } }
备注:关于引包问题
http://blog.youkuaiyun.com/jbxiaozi/article/details/7351768
sun.misc.BASE64Encoder找不到jar包的解决方法
解决方案1(推荐):
只需要在project build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。
解决方案2:
Windows -> Preferences -> Java -> Compiler -> Errors/Warnings ->
Deprecated and trstricted API -> Forbidden reference (access rules): -> change to warning
优快云代码下载:
http://download.youkuaiyun.com/detail/wangxsh42/8089377