java使用smtp协议发送邮件注意的问题

公司经常遇到发送邮件的问题,普通邮件发送就不说了,说一下无账号密码发送邮件的过程,在这里总结一下:

邮件收发协议:发送邮件使用smtp协议,收取邮件使用pop或imap协议;这里我们只讲发送邮件的smtp协议;

smtp发送邮件过程

这部分说明是从网上摘抄的,写的很详细,我就贴过来修改了一下:

使用smtp协议发送邮件给邮件服务器时规定了要做以下几件事:

  1、使用"ehlo"命令和连接上的smtp服务器打声招呼,例如:
     ehlo zqz
               命令格式为  “ehlo 当前计算机的hostname”; zqz即为当前计算机的主机名;

  2、使用"auth login"命令登录到Smtp服务器,登录使用的用户名和密码必须经过Base64加密,例如:
    ①、输入命令:auth login  
    ②、输入使用Base64加密过后的用户名:Z2FjbA==
    ③、输入Base64加密过后的密码:MTIzNDU2
            说明:好多企业内部邮箱不需要设置用户名密码,一般都是将发送邮件的服务器ip列入白名单,那么这一步就可以省略;

  3、指明邮件的发件人和收件人

    mail from:
    rcpt to:

   4、编写要发送的邮件内容,邮件的编写格式是有一定的规则的,一封格式良好的邮件应该包含邮件头和邮件的主体内容。

 邮件头使用下面的三个字段来指明:

  1. from字段用于指明邮件的发送人
  2. to字段用于指明邮件的收件人
  3. subject字段用于指明邮件的主题

   邮件的内容包含了这些信息之后才是一封格式良好的邮件。

    ①、输入"data"命令
      data
    ②、编写邮件内容
                    Cc:[email protected]                    ----邮件头   抄送给谁
      From:[email protected]              ----邮件头   邮件发送者
      To:[email protected]            ----邮件头   邮件接收者
      Subject:hello test         ----邮件头   邮件标题
                          ----空行
      hello test                 ----邮件的具体内容

  5、输入一个.告诉邮件服务器邮件内容已经写完了。
    .
  6、输入quit命令断开与邮件服务器的连接。
    quit
 

以上的6个步骤就是Smtp协议规定的发送一封Email必须要做的事情。

 

下面就用命令行来执行一下整个过程:

[C:\Users\Administrator]$ telnet smtp.tingyun.com 25

Host 'smtp.tingyun.com' resolved to 163.177.72.143.
Connecting to 163.177.72.143:25...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.

220 smtp.qq.com Esmtp QQ Mail Server         //连接成功后服务器主动推送的消息,220为响应代码,后面欢迎消息说明服务器的域名为smtp.qq.com ,协议为Esmtp ,服务器名为QQ Mail Server;

ehlo localhost                                         //此命令成功后,服务器推送支持的认证方式
250-smtp.qq.com
250-PIPELINING
250-SIZE 73400320
250-STARTTLS
250-AUTH LOGIN PLAIN                       //这里是服务器返回的支持的验证方式 LOGIN 和PLAIN两种方式
250-AUTH=LOGIN
250-MAILCOMPRESS
250 8BITMIME
auth login                                             //此命令向服务器发起认证请求
334 VXNlcm5hbWU6                           //334代表等待输入命令  后面字符串代表输入用户名 ,解码后就是Username:
ZXRwdGVzdEB0aW5neXVuLmNvbQ==           //base64的用户名    
334 UGFzc3dvcmQ6                            //334代表等待输入命令  后面字符串代表输入密码,解码之后就是Password:
VFl1bjAxMA==                                                 //base64的密码
235 Authentication successful            //235代表验证通过,如果验证失败则返回530
mail from:   //谁发送的邮件
250 Ok
rcpt to:<[email protected]>           //谁接收邮件
250 Ok
data                                                   //data命令代表邮件正文
354 End data with .       //354代表可以发送邮件正文,并提示邮件以"."结尾

 

From:[email protected]             //发送者
To:[email protected]                     //接收者
Cc:[email protected]                    //抄送
Subject:hello test                               //标题
Content-Type: text/plain

                                                           //回车空行 ,此行上面是head,下面是body
hello test.                                           //邮件正文
.                                                          //  .代表正文结束
250 Ok: queued as 

 

 

以上红色部分为我们自己需要输入的命令行。

 

qq邮箱收到的邮件:

 

hello test

 

发件人:etptest       
时   间:2018年5月9日(星期三) 下午5:36 纯文本 | 

收件人:

randolpha <[email protected]>

抄   送:

zhuqz 

 
 

hello test.

SMTP协议中HELO和EHLO

 


HELO是普通SMTP,不带身份验证,可以伪造邮件!一般如果不关闭SMTP的话,就可以制造垃圾邮件了,这个已经没有公司使这种方式了;

EHLO是ESMTP,带有身份验证,所以没法伪造。

 

 

 

java中SMTP协议发送邮件

 


SMTP协议发送邮件使用的是com.sun.mail.smtp.SMTPTransport这个类,建立连接,验证身份的逻辑在protocolConnect方法里面;
如果不设置mail.smtp.auth 和 mail.smtp.ehlo ,默认mail.smtp.auth = false,mail.smtp.ehlo=true;
相关的代码逻辑在com.sun.mail.smtp.SMTPTransport.protocolConnect()的613行:

 

 

 

       // setting mail.smtp.ehlo to false disables attempts to use EHLO
	boolean useEhlo =  PropUtil.getBooleanSessionProperty(session, "mail." + name + ".ehlo", true);
	// setting mail.smtp.auth to true enables attempts to use AUTH
	boolean useAuth = PropUtil.getBooleanSessionProperty(session, "mail." + name + ".auth", false);

判断是否需要执行auth login操作验证用户名和密码在第682行:
 

if ((useAuth || (user != null && passwd != null)) &&
		  (supportsExtension("AUTH") ||
		   supportsExtension("AUTH=LOGIN"))) {
		connected = authenticate(user, passwd);

注意这里的判断条件 ,如果mail.smtp.auth = true 或者 用户名和密码都不为null;
也就是在以下条件都会进程login验证:
1. mail.smtp.auth = true ;
2. mail.smtp.auth = false, 但是用户名和密码都不为null;

所以如果我们不去设置mail.smtp.auth参数(那么它默认就是false),只要将用户名和密码设置为null或者非null,即可让java决定是否需要执行login操作;所以建议不要设置mail.smtp.auth参数,只使用用户名和密码来控制是否执行login操作;

注意:
1. 对于不需要用户名和密码发送邮件的情况,需要将mail.smtp.auth = false或不设置(默认就是fasle),并把userName和password设置为null;

2. 对于exchange邮箱发送邮件,userName不要设置加@邮箱域名后面的内容,只需要@符号前的用户名即可;

状态码查询

500 格式错误,命令不可识别(此错误也包括命令行过长)
501 参数格式错误
502 命令不可实现
503 错误的命令序列
504 命令参数不可实现
211 系统状态或系统帮助响应
214 帮助信息
220 服务就绪
221 服务关闭传输信道
421 服务未就绪,关闭传输信道(当必须关闭时,此应答可以作为对任何命令的响应)
250 要求的邮件操作完成
251 用户非本地,将转发向
450 要求的邮件操作未完成,邮箱不可用(例如,邮箱忙)
550 要求的邮件操作未完成,邮箱不可用(例如,邮箱未找到,或不可访问)
451 放弃要求的操作;处理过程中出错
551 用户非本地,请尝试
452 系统存储不足,要求的操作未执行
552 过量的存储分配,要求的操作未执行
553 邮箱名不可用,要求的操作未执行(例如邮箱格式错误)
354 开始邮件输入,以.结束
554 操作失败

 

如果要使用SSL发送邮件:

 

mail.smtp.starttls.enable=true; mail.smtp.ssl.protocols=TLSv1.2;

mail.smtp.starttls.enable的说明:

If true, enables the use of the STARTTLS command (if supported by the server) to switch the connection to a TLS-protected connection before issuing any login commands. Note that an appropriate trust store must configured so that the client will trust the server's certificate. Defaults to false.

如果设置为true,  则在执行登陆命令前,会使用STRRTTLS命令选择使用TLS方式建连(前提是邮件服务器必须支持TLS方式)。

需要注意的是,在我们的客户端,必须将服务器端的证书配置到我们的信任列表里面(信任列表就是truststore,用来存放信任的证书的,不清楚是什么的需要去度娘一下);

默认值为false;

 

 

发送smtp邮件

下面是阿里云禁用25端口的情况下如何使用465端口smtps协议发送邮件

https://www.unixhot.com/article/303

你可能感兴趣的:(java)