Java代碼
/**
* 簡易的郵件客戶端程序,后期將逐步完善提供友好UI
* 測試發(fā)現不支持Gmail,Gmail SMTP采用了TSL/SSL協議
* 已知JavaMail可實現SSL協議。。。
*/
package mail;
/**
* @author Daniel Cheng
*
*/
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;
public class SMTPClient {
private boolean debug = true;
BASE64Encoder encode = new BASE64Encoder();// 自定義BASE64Encoder工具類用于加密字符串
public static void main(String[] args) throws UnknownHostException,
IOException {
MailMessage message = new MailMessage();
message.setFrom("test@163.com");// 發(fā)件人
message.setTo("test@hotmail.com,test@gmail.com,test@sina.com");// 多個收件人地址間用逗號隔開
String server = "smtp.163.com";// SMTP郵件服務器
message.setSubject("Java Mail Test");// 郵件主題
message.setContent("你好!這里是系統(tǒng)發(fā)出的JAVA MAIL測試,請勿回復。");// 郵件內容
message.setDataFrom("Sender");// 發(fā)件人,在郵件的發(fā)件人欄目中顯示
message.setDataTo("Receiver");// 收件人,在郵件的收件人欄目中顯示
message.setUser("test@163.com");// 登陸的郵箱賬號
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("已經建立連接!");
}
}
// 注冊到郵件服務器
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("已發(fā)送命令:" + str);
}
return getResult(in);
}
public int getResult(BufferedReader in) {
String line = "";
try {
line = in.readLine();
if (debug) {
System.out.println("服務器返回狀態(tài):" + line);
}
} catch (Exception e) {
e.printStackTrace();
}
// 從服務器返回消息中讀出狀態(tài)碼,將其轉換成整數返回
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:<" + source + ">", in, out);
if (result != 250) {
throw new IOException("指定源地址錯誤");
}
}
// 設置郵件收件人。多郵件發(fā)送用","隔開
public void rcpt(String touchman, BufferedReader in, BufferedWriter out)
throws IOException {
String[] mailList = touchman.split(",");
if (mailList.length > 1) {
for (String touch : mailList) {
connectionServer(touch,in,out);
}
}else
connectionServer(touchman,in,out);
}
private void connectionServer(String touch, BufferedReader in, BufferedWriter out)
throws IOException {
int result;
result = sendServer("RCPT TO:<" + touch + ">", 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應答后,繼續(xù)輸入郵件內容
if (result != 354) {
throw new IOException("不能發(fā)送數據");
}
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();
// 句號加回車結束郵件內容輸入
result = sendServer(".", in, out);
System.out.println(result);
if (result != 250) {
throw new IOException("發(fā)送數據錯誤");
}
}
// 退出
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;
}
}
Java代碼
/**
* 郵件實體POJO類
*/
package mail;
/**
* @author Daniel Cheng
*
*/
public class MailMessage {
private String from;
private String to;
private String subject;
private String content;
private String dataFrom;
private String dataTo;
private String user;
private String password;
/**
*
*/
public MailMessage() {
super();
// TODO Auto-generated constructor stub
}
/**
* @param from
* @param to
* @param subject
* @param content
* @param dataFrom
* @param dataTo
* @param user
* @param password
*/
public MailMessage(String from, String to, String subject, String content,
String dataFrom, String dataTo, String user, String password) {
super();
this.from = from;
this.to = to;
this.subject = subject;
this.content = content;
this.dataFrom = dataFrom;
this.dataTo = dataTo;
this.user = user;
this.password = password;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
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 getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Java代碼
/**
* BASE64Encoder加密類
*/
package mail;
/**
* @author Daniel Cheng
*
*/
public class BASE64Encoder {
private static char[] codec_table = { 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', '+', '/' };
public BASE64Encoder() {
}
public String encode(byte[] a) {
int totalBits = a.length * 8;
int nn = totalBits % 6;
int curPos = 0;// process bits
StringBuffer toReturn = new StringBuffer();
while (curPos < totalBits) {
int bytePos = curPos / 8;
switch (curPos % 8) {
case 0:
toReturn.append(codec_table[(a[bytePos] & 0xfc) >> 2]);
break;
case 2:
toReturn.append(codec_table[(a[bytePos] & 0x3f)]);
break;
case 4:
if (bytePos == a.length - 1) {
toReturn
.append(codec_table[((a[bytePos] & 0x0f) << 2) & 0x3f]);
} else {
int pos = (((a[bytePos] & 0x0f) << 2) | ((a[bytePos + 1] & 0xc0) >> 6)) & 0x3f;
toReturn.append(codec_table[pos]);
}
break;
case 6:
if (bytePos == a.length - 1) {
toReturn
.append(codec_table[((a[bytePos] & 0x03) << 4) & 0x3f]);
} else {
int pos = (((a[bytePos] & 0x03) << 4) | ((a[bytePos + 1] & 0xf0) >> 4)) & 0x3f;
toReturn.append(codec_table[pos]);
}
break;
default:
//never hanppen
break;
}
curPos+=6;
}
if(nn==2)
{
toReturn.append("==");
}
else if(nn==4)
{
toReturn.append("=");
}
return toReturn.toString();
}
}