java发送邮件354_基于SMTP的JAVA邮件发送程序
這個程序沒有使用JavaMail API,而是根據(jù)SMTP協(xié)議的要求直接處理協(xié)議的細節(jié)發(fā)送郵件,雖然比較麻煩了一些,但是對了解郵件協(xié)議的細節(jié)很有幫助的。
本文分兩部分,第一部分是SMTP命令介紹(這個從別的地方抄的,嘿嘿);第二部分通過一個實例真正理解一下發(fā)送郵件的過程。
一:SMTP 命令簡介
什么是 SMTP
SMTP (Simple Mail Transfer Protocol) : 電子郵件從客戶機傳輸?shù)椒?wù)器或從某一個服務(wù)器傳輸?shù)搅硪粋€服務(wù)器使用的傳輸協(xié)議。 SMTP 是請求/響應(yīng)協(xié)議,命令和響應(yīng)都是基于 ASCII 文本,并以 CR 和 LF 符結(jié)束。響應(yīng)包括一個表示返回狀態(tài)的三位數(shù)字代碼。SMTP 在 TCP 協(xié)議 25 端口監(jiān)聽連接請求。
什么是 ESMTP
ESMTP (Extended SMTP),顧名思義,擴展 SMTP 就是對標準 SMTP 協(xié)議進行的擴展。它與 SMTP 服務(wù)的區(qū)別僅僅是,使用 SMTP 發(fā)信不需要驗證用戶帳戶,而用 ESMTP 發(fā)信時,服務(wù)器會要求用戶提供用戶名和密碼以便驗證身份。驗證之后的郵件發(fā)送過程與 SMTP 方式?jīng)]有兩樣。
SMTP 命令包括:
HELO 向服務(wù)器標識用戶身份。發(fā)送者能欺騙,說謊,但一般情況下服務(wù)器都能檢測到。
EHLO 向服務(wù)器標識用戶身份。發(fā)送者能欺騙,說謊,但一般情況下服務(wù)器都能檢測到。
MAIL FROM 命令中指定的地址是發(fā)件人地址
RCPT TO 標識單個的郵件接收人;可有多個 RCPT TO;常在 MAIL 命令后面。
DATA 在單個或多個 RCPT 命令后,表示所有的郵件接收人已標識,并初始化數(shù)據(jù)傳輸,以 CRLF.CRLF 結(jié)束
VRFY 用于驗證指定的用戶/郵箱是否存在;由于安全方面的原因,服務(wù)器常禁止此命令
EXPN 驗證給定的郵箱列表是否存在,擴充郵箱列表,也常被禁用
HELP 查詢服務(wù)器支持什么命令
NOOP 無操作,服務(wù)器應(yīng)響應(yīng) OK
RSET 重置會話,當前傳輸被取消
QUIT 結(jié)束會話
連接到 Postfix 使用 SMTP 命令發(fā)送郵件
例如:安裝 Postfix 的郵件服務(wù)器IP是192.168.0.1 (藍色字體內(nèi)容由客戶端輸入,紅色字體內(nèi)容是服務(wù)返回的)
telnet 192.168.0.1 25------------------------------------------------- 使用 telnet 命令連接服務(wù)器 25 端口
helo test.com -----------------------------------------------------------向服務(wù)器標識用戶身份發(fā)送 mail from 命令
ehlo test.com ----------------------------------------------------------- ESMTP 命令,發(fā)信需要認證。
auth login ----------------------------------------------------------------進行用戶身份認證
334 VXNlcm5hbWU6
Y29zdGFAYW1heGl0Lm5ldA==----------------------------------- BASE64 加密后的用戶名
334 UGFzc3dvcmQ6
MTk4MjIxNA== -------------------------------------------------------- BASE64 加密后的密碼
235 authentication successfully-------------------------------- 身份認證成功
(535 authentication failed--------------------------------- ------身份認證失敗)
發(fā)到本系統(tǒng)中域名下的賬戶可跳過身份認證。
test1@domain.com
250 ok----------------------------------------------------- ----------命令執(zhí)行成功
test2@domain.com
250 ok----------------------------------------------------- ----------命令執(zhí)行成功
data ------------------------------------------------------- -----------數(shù)據(jù)傳輸初始化
354 End data with .----------------------------------------- -----開始傳輸數(shù)據(jù)
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.
.------------------------------------------------------------ 數(shù)據(jù)內(nèi)容,包括BASE64加密后的郵件內(nèi)容, 以 CRLF.CRLF 結(jié)束數(shù)據(jù)傳輸
250 OK: queued as 2F6DE3929--------------------------------- 命令執(zhí)行成功
quit ------------------------------------------------------- 結(jié)束會話
221 Bye
Connection closed by foreign host .------------------------- 斷開連接
以上就是一個郵件發(fā)送的基本的命令。
再說一下郵件發(fā)送的基本過程:
如果你的郵件地址是a@host.com,而你要用這個郵箱發(fā)送一封郵件到to@tohost.com,你需要連接到服務(wù)器host.com上,當然這個連接可能需要認證,現(xiàn)在基本上都要驗證,然后是發(fā)送郵件到服務(wù)器host.com上,關(guān)閉連接。在host.com上,你所發(fā)送的郵件進入發(fā)送隊列中,輪到你要發(fā)送的郵件時,host.com主機再聯(lián)系tohost.com,將郵件傳輸?shù)椒?wù)器tohost.com上。
二:實例應(yīng)用
-----------------------------------------------------------------------------------------------------------------------
MailMessage.java
----------------------------------------
//這個類其實就是一個基本的JavaBean,用于完成一些基本信息的設(shè)置,也可以不要這個東西,直接在程序中寫明就可以,不過這樣條理較清楚一些,而且修改也方便一些.
package mail;
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 .java
------------------------------
//主要的功能就在這里面完成了
package mail;
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.util.StringTokenizer;
import sun.misc.BASE64Encoder;
public class SMTPClient {
private boolean debug=true;
BASE64Encoder encode=new BASE64Encoder();//用于加密后發(fā)送用戶名和密碼
public static void main(String[] args) throws UnknownHostException, IOException {
// TODO Auto-generated method stub
MailMessage message=new MailMessage();
message.setFrom("mailto:wasingmon@163.com%22);//發(fā)件人
message.setTo("mailto:wasingmon@eyou.com%22);//收件人
String server="smtp.163.com";//郵件服務(wù)器
message.setSubject("test");//郵件主題
message.setContent("test");//郵件內(nèi)容
message.setDatafrom("mailto:wangxingmou@eyou.com%22);//發(fā)件人,在郵件的發(fā)件人欄目中顯示
message.setDatato("mailto:wasingmon@163.com%22);//收件人,在郵件的收件人欄目中顯示
message.setUser("wasingmon");//登陸郵箱的用戶名
message.setPassword("");//登陸郵箱的密碼
SMTPClient smtp=new SMTPClient(server,25);
boolean flag;
flag=smtp.sendMail(message,server);
if(flag){
System.out.println("郵件發(fā)送成功!");
}
else{
System.out.println("郵件發(fā)送失敗!");
}
}
private Socket socket;
public SMTPClient(String server,int port) throws UnknownHostException, IOException{
try{
socket=new Socket(server,25);
}catch(SocketException e){
System.out.println(e.getMessage());
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.println("已經(jīng)建立連接!");
}
}
//注冊到郵件服務(wù)器
public void helo(String server,BufferedReader in,BufferedWriter out) throws IOException{
int result;
result=getResult(in);
//連接上郵件服務(wù)后,服務(wù)器給出220應(yīng)答
if(result!=220){
throw new IOException("連接服務(wù)器失敗");
}
result=sendServer("HELO "+server,in,out);
//HELO命令成功后返回250
if(result!=250)
{
throw new IOException("注冊郵件服務(wù)器失敗!");
}
}
private int sendServer(String str,BufferedReader in,BufferedWriter out) throws IOException{
out.write(str);
out.newLine();
out.flush();
if(debug)
{
System.out.println("已發(fā)送命令:"+str);
}
return getResult(in);
}
public int getResult(BufferedReader in){
String line="";
try{
line=in.readLine();
if(debug){
System.out.println("服務(wù)器返回狀態(tài):"+line);
}
}catch(Exception e){
e.printStackTrace();
}
//從服務(wù)器返回消息中讀出狀態(tài)碼,將其轉(zhuǎn)換成整數(shù)返回
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("驗證失敗!");
}
}
//開始發(fā)送消息,郵件源地址
public void mailfrom(String source,BufferedReader in,BufferedWriter out) throws IOException{
int result;
result=sendServer("MAIL FROM:",in,out);
if(result!=250){
throw new IOException("指定源地址錯誤");
}
}
// 設(shè)置郵件收件人
public void rcpt(String touchman,BufferedReader in,BufferedWriter out) throws IOException{
int result;
result=sendServer("RCPT TO:",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應(yīng)答后,繼續(xù)輸入郵件內(nèi)容
if(result!=354){
throw new IOException("不能發(fā)送數(shù)據(jù)");
}
out.write("From: "+from);
out.newLine();
out.write("To: "+to);
out.newLine();
out.write("Subject: "+subject);
out.newLine();
out.newLine();
out.write(content);
out.newLine();
//句號加回車結(jié)束郵件內(nèi)容輸入
result=sendServer(".",in,out);
System.out.println(result);
if(result!=250)
{
throw new IOException("發(fā)送數(shù)據(jù)錯誤");
}
}
//退出
public void quit(BufferedReader in,BufferedWriter out) throws IOException{
int result;
result=sendServer("QUIT",in,out);
if(result!=221){
throw new IOException("未能正確退出");
}
}
//發(fā)送郵件主程序
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;
}
}
因為現(xiàn)在一般SMTP服務(wù)器都需要SMTP驗證,所以本例子中也加入了這個驗證,要不然郵件時發(fā)不出去的(剛開始我就這樣)。
END!
總結(jié)
以上是生活随笔為你收集整理的java发送邮件354_基于SMTP的JAVA邮件发送程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ApkTool2.34 打包经验
- 下一篇: PoW算法