分享
 
 
 

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

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

//------------------------------------------------------------------

// \\\|///

// \\ -^- //

// ( @ @ )

// +----------------------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;

}

}///:~

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有