正好遇到这方面的问题,写出来,分享一下。
这个程序没有使用JavaMail API,而是根据SMTP协议的要求直接处理协议的细节发送邮件,虽然比较麻烦了一些,但是对了解邮件协议的细节很有帮助的。
本文分两部分,第一部分是SMTP命令介绍(这个从别的地方抄的,嘿嘿);第二部分通过一个实例真正理解一下发送邮件的过程。
一: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上。
二:实例应用
-----------------------------------------------------------------------------------------------------------------------
这是一个简单的发送邮件的原代码,只是完成对文本的发送,这是主要的部分,至于页面部分我想大家能自己写出来,在程序中调用我这个类就可以了,我只是对163和sohu的进行了测试,都可以使用,其他的邮箱也没有进行测试,使用前只需要添加两个相关jar包,mail.jar和activation.jar,其他的jar包应该不需要说了,回过头来看看也比较简单,却费了我很长的时间,我感觉网上的一些文章copy的太多,有头没有有尾,有尾没有头,很少有一个测试成功的,我写的比较粗,也没有参数传送,大家可以自己扩展一下,希望能给向我这样的人一些帮助
主程序调用:
javaMail mail = new javaMail();
mail.sendMail();
类代码:
import java.util.Date;
import java.util.Properties;
import javax.servlet.*;
import javax.mail.Session;
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Message;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.InternetAddress;
import javax.mail.Transport;
public class javaMail {
private Properties properties;
private Session mailSession;
private MimeMessage mailMessage;
private Transport trans;
public javaMail() {
}
public void sendMail() {
try {
properties = new Properties();
//设置邮件服务器
properties.put("mail.smtp.host", "发邮件的服务器");
//验证
properties.put("mail.smtp.auth", "true");
//根据属性新建一个邮件会话
mailSession = Session.getInstance(properties,
new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("你邮箱的用户名称",
"用户密码");
}
});
mailSession.setDebug(true);
//建立消息对象
mailMessage = new MimeMessage(mailSession);
//发件人
mailMessage.setFrom(new InternetAddress("发邮件的邮箱"));
//收件人
mailMessage.setRecipient(MimeMessage.RecipientType.TO,
new InternetAddress("收邮件的邮箱"));
//主题
mailMessage.setSubject("测试");
//内容
mailMessage.setText("test");
//发信时间
mailMessage.setSentDate(new Date());
//存储信息
mailMessage.saveChanges();
//
trans = mailSession.getTransport("smtp");
//发送
trans.send(mailMessage);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}
注:搜狐测试通过(smtp.sohu.com)
示例2
public class JavaMailTest {
public static void main(String args[]) throws MessagingException {
String smtpHost = "smtp.sohu.com";
String from = "javamailfrom@sohu.com";
String to = "javamailto@sohu.com";
Properties properties = System.getProperties();
Session session = Session.getInstance(properties);
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject("JavaMail Example");
message.setText("Did it work?");
Transport transport = session.getTransport("smtp");
transport.connect(smtpHost, "用户名", "密码");
transport.sendMessage(message, message.getAllRecipients());
transport.close();
}
}
可能会出现如下错误
'550 5.1.1 <XXXX@ygsoft.com>: Recipient address rejected: User unknown in virtual mailbox table',
你发送的帐号在邮件系统内不存在,请检查你的邮件地址是否输入有误
'554 5.7.1 <XXXX@ygsoft.com>: Sender address rejected: Access denied',
你的邮箱是内部帐号,你所发送的地址不在授权域之内
'553 5.7.1 <XXXX@ygsoft.com>: Sender address rejected: not logged in',
发送邮件需要SMTP身份验证,你的帐号SMTP身份验证部分没有设置正确,请检查配置
'454 4.7.1 <unknown[***.***.***.***]>: Client host rejected: Access denied'
你的IP被管理员屏蔽,请检查你部的机器是否被感染病毒自动发送邮件