• 软件测试技术
  • 软件测试博客
  • 软件测试视频
  • 开源软件测试技术
  • 软件测试论坛
  • 软件测试沙龙
  • 软件测试资料下载
  • 软件测试杂志
  • 软件测试人才招聘
    暂时没有公告

字号: | 推荐给好友 上一篇 | 下一篇

开放源码-SMTP发信客户端 for Java

发布: 2007-7-04 13:34 | 作者: admin | 来源:  网友评论 | 查看: 9次 | 进入软件测试论坛讨论

领测软件测试网 //------------------------------------------------------------------
// \\\|///
// \\ -^- //
// ( @ @ )
// +----------------------oOOo-(_)-oOOo---------------------+
//
// FREE SOFTWARE WRITEN BY NAVY, COPYLEFT (C) 2002
// SmtpClient Class 1.0
// Use smtp server with user authorization
// All rights reserved.
//
// Oooo
// +---------------------- oooO---( )---------------------+
// ( ) ) /
// \ ( (_/
// \_)
//------------------------------------------------------------------


package encrypt;

import java.io.*;
import java.net.*;
import java.util.Vector;
//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;
import encrypt.Base64;

/***
* 标准SMTP发信类
* <p>
* 标准的纯JAVA的SMTP发信客户端程序,支持用户认证。
* <p>
* <p>
* @author Naven
* @see SmtpClient
***/

public class SmtpClient
{
//protected static final Log log = LogFactory.getLog(SmtpClient.class);

private static final String CMD_HELO = "HELO ";
private static final String CMD_AUTH_LOGIN = "AUTH LOGIN ";
private static final String CMD_MAIL_FROM = "MAIL FROM: ";
private static final String CMD_RCPT_TO = "RCPT TO: ";
private static final String CMD_DATA = "DATA";
private static final String CMD_HELP = "HELP";
private static final String CMD_RSET = "RSET";
private static final String CMD_NOOP = "NOOP";
private static final String CMD_QUIT = "QUIT";
private static final String END_OF_MAIL = "\r\n.\r\n";

private static final String RCV_SERVOK = "220"; // 220 服务就绪
private static final String RCV_HELO = "250"; // 250 要求的邮件操作完成
private static final String RCV_AUTH_LOGIN = "334";
private static final String RCV_AUTH_USER = "334";
private static final String RCV_AUTH_PASSWD = "334";
private static final String RCV_AUTH_OK = "235";
private static final String RCV_MAIL_FROM = "250";
private static final String RCV_RCPT_TO = "250";
private static final String RCV_DATA = "354";
private static final String RCV_SEND_END = "250";
private static final String RCV_RSET = "250";
private static final String RCV_NOOP = "250";
private static final String RCV_QUIT = "221"; // 221 服务关闭传输信道

private static final int SEND_BLOCK_SIZE = 1024; // 每次发送信件内容的块的大小

/**
* BASE64加密对象
*/
//private Base64 base64 = new Base64();


private static final int _NOTHING_SPECIAL_STATE = 0;
private static final int _LAST_WAS_CR_STATE = 1;
private static final int _LAST_WAS_NL_STATE = 2;

/**
* 记录处理邮件正文数据发送的状态
*/
private int _state = 0;

/**
* 用于处理邮件正文数据发送同步处理的锁定
*/
private Integer lock = new Integer(0);

/**
* client socket
*/
private Socket socketSmtp = null;

/**
* socket out printwriter
*/
private PrintWriter sout = null;

/**
* socket int reader
*/
private BufferedReader sin = null;

/**
* smtp email server address
*/
private String smtpServer = null;

/**
* email from user for smtp server
*/
private String user = null;

/**
* user password
*/
private String passwd = null;

/**
* sender''s email address
*/
private String sender = null;

/**
* email from user for smtp server, base64 encode
*/
private String encryptUser = null;

/**
* user password, base64 encode
*/
private String encryptPasswd = null;

/**
* client localhost
*/
private String localHost = null;

/**
* error message
*/
private String errorString = "NO ERROR";


/***
* 初始化发信类
* <p>
* @param server SMTP服务器地址
* @param sender SMTP发信人邮件地址
***/
public SmtpClient(String server, String sender)
{
this(server, null, null, sender);
}

/***
* 初始化发信类
* <p>
* @param server SMTP服务器地址
* @param user SMTP发信人认证用户名
* @param passwd SMTP发信人认证密码
* @param sender SMTP发信人邮件地址
***/
public SmtpClient(String server, String user, String passwd, String sender)
{
this.smtpServer = server;
this.user = user;
this.passwd = passwd;
this.sender = sender;

if( this.user != null && this.passwd != null )
{
Base64 base64 = new Base64();

// base64 encode begain
byte[] buser = user.getBytes();
byte[] bpasswd= passwd.getBytes();

base64.startEncode();
base64.encode(buser, buser.length);
base64.endEncode();
this.encryptUser = new String(base64.getEncodedResult());

base64.startEncode();
base64.encode(bpasswd, bpasswd.length);
base64.endEncode();
this.encryptPasswd = new String(base64.getEncodedResult());
}
}

/***
* 获取处理的错误信息
* <p>
* @return 错误信息
***/
public String getError() {
return errorString;
}

/***
* 当出错时抛出错误信息
* <p>
* @param e 错误异常
***/
private void onError(Exception e)
{
this.errorString = e.getMessage();
//log.error("onError() " + this.errorString);
//if( log.isDebugEnabled() ) {
// log.debug("onError()", e);
//}
}

/***
* 检查SMTP协议通讯收到的信息是否成功,即以指定返回代号开头,SMTP协议标准。
* <p>
* @param rcvmsg SMTP协议通讯收到的信息
* @param code SMTP协议通讯返回代号
* @exception IOException 失败时抛出异常
***/
private void check(String rcvmsg, String code)
throws IOException
{
if( code == null || code.length() == 0 ) return;
if( rcvmsg == null || rcvmsg.startsWith(code) == false )
throw ( new IOException(rcvmsg) );
}

/***
* 检查SMTP协议通讯收到的信息是否成功,即以指定返回代号数组中任意个开头,SMTP协议标准。
* <p>
* @param rcvmsg SMTP协议通讯收到的信息
* @param codes SMTP协议通讯返回代号数组
* @exception IOException 失败时抛出异常
***/
private void check(String rcvmsg, String[] codes)
throws IOException
{
if( codes == null || codes.length == 0 ) return;
boolean result = false;
for( int i=0; rcvmsg != null && i < codes.length && codes[i] != null; i++ ) {
if( rcvmsg.startsWith(codes[i]) == false ) {
result = true;
break;
}
}
if(!result) throw ( new IOException(rcvmsg) );
}

/***
* 往SMTP服务器写邮件正文数据的一个字节,并处理数据中“\r\n.”需转换成“\r\n..”的情况。
* <p>
* @param ch 写入的一个字节
* @exception IOException 失败时抛出异常
***/
private void write(int ch)
throws IOException
{
synchronized (lock)
{
switch (ch)
{
case ''\r'':
_state = _LAST_WAS_CR_STATE;
sout.write(''\r'');
return ;
case ''\n'':
if (_state != _LAST_WAS_CR_STATE)
sout.write(''\r'');
sout.write(''\n'');
_state = _LAST_WAS_NL_STATE;
return ;
case ''.'':
// Double the dot at the beginning of a line
if (_state == _LAST_WAS_NL_STATE)
sout.write(''.'');
// Fall through
default:
_state = _NOTHING_SPECIAL_STATE;
sout.write(ch);
return ;
}
}
}

/***
* 往SMTP服务器写邮件正文数据的一段数据,并处理数据中“\r\n.”需转换成“\r\n..”的情况。
* <p>
* @param buffer 写入的数据缓冲
* @param offset 写入的数据缓冲的偏移
* @param length 写入的数据缓冲的长度
* @exception IOException 失败时抛出异常
***/
private void write(char[] buffer, int offset, int length)
throws IOException
{
synchronized (lock)
{
while (length-- > 0)
write(buffer[offset++]);
}
}

/***
* 往SMTP服务器写邮件正文数据的一段数据,并处理数据中“\r\n.”需转换成“\r\n..”的情况。
* <p>
* @param buffer 写入的数据缓冲
* @exception IOException 失败时抛出异常
***/
private void write(char[] buffer)
throws IOException
{
write(buffer, 0, buffer.length);
}

/***
* 往SMTP服务器写邮件正文数据的一段数据,并处理数据中“\r\n.”需转换成“\r\n..”的情况。
* <p>
* @param string 写入的数据字符串
* @exception IOException 失败时抛出异常
***/
private void write(String string)
throws IOException
{
write(string.toCharArray());
}

/***
* 将SOCKET STREAM缓冲区的数据刷新,提交出去。
* <p>
* @exception IOException 失败时抛出异常
***/
private void flush()
throws IOException
{
synchronized (lock)
{
sout.flush();
}
}

/***
* 往SMTP服务器写一行数据。
* <p>
* @param msg 写入的一行数据字符串
* @exception IOException 失败时抛出异常
***/
private void sendln(String msg)
throws IOException
{
if( msg == null ) msg = "";

sout.println(msg);
sout.flush();

//if( log.isDebugEnabled() ) {
// log.debug("sendln() ==>: "+msg);
//}
}

/***
* 往SMTP服务器写字符串数据。
* <p>
* @param msg 写入的字符串
* @exception IOException 失败时抛出异常
***/
private void send(String msg)
throws IOException
{
if( msg == null ) msg = "";

sout.write(msg);
sout.flush();

//if( log.isDebugEnabled() ) {
// log.debug("send() ==>: "+msg);
//}
}

/***
* 往SMTP服务器写一段大字符串数据。
* <p>
* @param text 写入的字符串数据
* @exception IOException 失败时抛出异常
***/
private void sendtext(String text)
throws IOException
{
if( text == null ) text = "";

if( text.length() > SEND_BLOCK_SIZE ) {
int i = 0;
while( i <= text.length() ) {
if( (i + SEND_BLOCK_SIZE) < text.length() )
write(text.substring(i, (i+SEND_BLOCK_SIZE)));
else
write(text.substring(i));
flush();
i = i + SEND_BLOCK_SIZE;
}

//if( log.isDebugEnabled() ) {
// log.debug("sendtext() ==>: <Email Mesg> "+text.length()+" chars");
//}
}
else {
write(text);
flush();

//if( log.isDebugEnabled() ) {
// log.debug("sendtext() ==>: "+text);
//}
}
}

/***
* 从SMTP服务器接收一行字符串数据。
* <p>
* @return 读取的字符串数据
* @exception IOException 失败时抛出异常
***/
private String receive()
throws IOException
{
String rcvmsg = sin.readLine();
//if( log.isDebugEnabled() ) {
// log.debug("receive() <==: " + rcvmsg);
//}
return rcvmsg;
}

/***
* 从SMTP服务器接收一行字符串数据,并判断是否是成功的返回值。
* <p>
* @param code 正确的SMTP协议代码
* @return 读取的字符串数据
* @exception IOException 失败时抛出异常
***/
private String receive(String code)
throws IOException
{
String rcvmsg = receive();
check(rcvmsg, code);
return rcvmsg;
}

/***
* 从SMTP服务器接收一行字符串数据,并判断是否是成功的返回值数组的一个。
* <p>
* @param codes 正确的SMTP协议代码数组
* @return 读取的字符串数据
* @exception IOException 失败时抛出异常
***/
private String receive(String[] codes)
throws IOException
{
String rcvmsg = receive();
check(rcvmsg, codes);
return rcvmsg;
}

/***
* 连接SMTP服务器并发送用户名和密码认证。
* <p>
* @return 返回成功失败结果
* @exception IOException 失败时抛出异常
***/
public boolean connect()
{
// connect to smtp server and autherize
try{
// get localhost name
localHost = InetAddress.getLocalHost().getHostName();
//if( log.isDebugEnabled() ) {
// log.debug("connect() localhost: " + localHost);
//}

// connect to smtp server
socketSmtp = new Socket(smtpServer, 25);
sout = new PrintWriter(new OutputStreamWriter(socketSmtp.getOutputStream()));
sin = new BufferedReader(new InputStreamReader(socketSmtp.getInputStream()));
receive(RCV_SERVOK);

// hello
sendln(CMD_HELO + localHost);
receive(RCV_HELO);

if( encryptUser != null && encryptPasswd != null )
{
// auth login
sendln(CMD_AUTH_LOGIN);
receive(RCV_AUTH_LOGIN);

// base64 encode end
sendln(encryptUser);
receive(RCV_AUTH_USER);
sendln(encryptPasswd);
receive(RCV_AUTH_OK);
}
}
catch(IOException e) {
onError(e);
closeall();
return false;
}

return true;
}

/***
* 连接SMTP服务器并发送邮件。
* <p>
* @param to 收件人邮件地址
* @param msg 邮件数据
* @return 返回成功失败结果
* @exception IOException 失败时抛出异常
***/
public boolean sendMail(String to, String msg) {
return sendMail(to, msg, null);
}

/***
* 连接SMTP服务器并发送邮件。
* <p>
* @param to 收件人邮件地址
* @param msg 邮件数据
* @param cc CC收件人邮件地址
* @return 返回成功失败结果
* @exception IOException 失败时抛出异常
***/
public boolean sendMail(String to, String msg, Vector cc)
{
if( socketSmtp == null || sout == null || sin == null ) {
closeall();
if( !connect() ) return false;
}

boolean retval = false;
int count = 0;
// try send for 3 times if error
while( retval == false && count < 3 ) {
try {
// mail from
sendln(CMD_MAIL_FROM + sender);
receive(RCV_MAIL_FROM);

// send to
sendln(CMD_RCPT_TO + to);
receive(RCV_RCPT_TO);

// perform cc
int ccSize = 0;
if(cc != null && (ccSize = cc.size()) > 0){
for(int i = 0; i < ccSize; i ++){
sendln(CMD_RCPT_TO + (String)cc.elementAt(i));
receive(RCV_RCPT_TO);
}
}
// end cc

// begain send mail data
sendln(CMD_DATA);
receive(RCV_DATA);
sendtext(msg);
sendln(END_OF_MAIL);
receive(RCV_SEND_END);

// send success
//receive(); // I dont know why 263.net.cn need receve again
retval = true;
}
catch(IOException e) {
onError(e);
retval = false;
count ++;
try{
// reset and send again
sendln(CMD_RSET);
receive(RCV_RSET);
}
catch(Exception e2) {
//log.error("sendMail()", e2);
break;
}
}
}

return retval;
}

/***
* 关闭与SMTP服务器连接。
* <p>
***/
private void closeall()
{
try {
if( sout != null ) {
sout.close(); sout = null;
}
if( sin != null ) {
sin.close(); sin = null;
}
if( socketSmtp != null ) {
socketSmtp.close(); socketSmtp = null;
}
}
catch(IOException e) {
//log.error("closeall()", e);
}
}

/***
* 关闭与SMTP服务器连接并释放资源。
* <p>
***/
public void release()
{
close();

this.socketSmtp = null; // client socket
this.sout = null; // socket out printstream
this.sin = null; // socket int reader
this.smtpServer = null; // smtp email server address
this.user = null; // email from user for smtp server
this.passwd = null; // user password
this.sender = null; // sender''s email address
this.encryptUser = null; // base64 encode
this.encryptPasswd = null; // base64 encode
this.localHost = null; // client localhost

this.errorString = "NO ERROR";
}

/***
* 发送QUIT命令并关闭与SMTP服务器连接。
* <p>
***/
public boolean close()
{
boolean retval = true;

if( sout != null && sin != null ) {
try {
// send finish quit
sendln(CMD_QUIT);
//receive();
retval = true;
}
catch(IOException e) {
retval = false;
//log.error("close()", e);
}
}
closeall();

return retval;
}

public String toString() {
return getClass().getName() +
" Server: " + smtpServer + " User: " + user +
" Passwd: " + passwd + " Sender: " + sender;
}

}///:~

延伸阅读

文章来源于领测软件测试网 https://www.ltesting.net/


关于领测软件测试网 | 领测软件测试网合作伙伴 | 广告服务 | 投稿指南 | 联系我们 | 网站地图 | 友情链接
版权所有(C) 2003-2010 TestAge(领测软件测试网)|领测国际科技(北京)有限公司|软件测试工程师培训网 All Rights Reserved
北京市海淀区中关村南大街9号北京理工科技大厦1402室 京ICP备2023014753号-2
技术支持和业务联系:info@testage.com.cn 电话:010-51297073

软件测试 | 领测国际ISTQBISTQB官网TMMiTMMi认证国际软件测试工程师认证领测软件测试网