服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

用java实现smtp服务器



    电子邮件传递可以由多种协议来实现。目前,在internet 网上最流行的三种电子邮件协议是smtp、pop3 和 imap,下面分别简单介绍。

  ◆ smtp 协议

  简单邮件传输协议(simple mail transfer protocol,smtp)是一个运行在tcp/ip之上的协议,用它发送和接收电子邮件。smtp 服务器在默认端口25上监听。smtp客户使用一组简单的、基于文本的命令与smtp服务器进行通信。在建立了一个连接后,为了接收响应,smtp客户首先发出一个命令来标识它们的电子邮件地址。如果smtp服务器接受了发送者发出的文本命令,它就利用一个ok响应和整数代码确认每一个命令。客户发送的另一个命令意味着电子邮件消息体的开始,消息体以一个圆点“.”加上回车符终止。

  ◆ pop3 协议

  邮局协议(post office protocol version 3,pop3)提供了一种对邮件消息进行排队的标准机制,这样接收者以后才能检索邮件。pop3服务器也运行在tcp/ip之上,并且在默认端口110上监听。在客户和服务器之间进行了初始的会话之后,基于文本的命令序列可以被交换。pop3客户利用用户名和口令向pop3服务器认证。pop3中的认证是在一种未加密的会话基础之上进行的。pop3客户发出一系列命令发送给pop3服务器,如:请求客户邮箱队列的状态、请求列出的邮箱队列的内容和请求检索实际的消息。pop3代表一种存储转发类型的消息传递服务。现在,大部分邮件服务器都采用smtp发送邮件,同时使用pop3接收电子邮件消息。

  ◆ imap 协议

  internet 消息访问协议(internet message access protocol,imap)是一种电子邮件消息排队服务,它对pop3的存储转发限制提供了重要的改进。imap也使用基于文本命令的语法在tcp/ip上运行,imap服务器一般在默认端口143监听。imap服务器允许imap客户下载一个电子邮件的头信息,并且不要求将整个消息从服务器下载至客户,这一点与pop3是相同的。imap服务器提供了一种排队机制以接收消息,同时必须与smtp相结合在一起才能发送消息。

  下面以smtp发送电子邮件为例讲解怎样用java 实现smtp 服务器应用功能,从而完成邮件的发送的。

  smtp 命令

  smtp协议是目前网上流行的发送e-mail的协议,smtp协议共有14条命令。不过,发一封e-mail只需用如下5条命令就足够了,分别为:

  ◆ helo <sp> <domain> <crlf> ,与smtp服务器握手,传送本机域名;

  ◆ mail <sp> from:<reverse-path> <crlf>,传送发信者的信箱名称;

  ◆ rcpt <sp> to:<forward-path> <crlf>,传送接收者的信箱名称;

  ◆ data <crlf>,发送信件数据(包括信头和信体);

  ◆ quit <crlf>,退出与smtp服务器的连接。

  编程思路

  首先我们设计一个邮件发送程序的交互界面,界面中包括用户输入邮件的收件人、发信人和主题组件的单行文本框,书写邮件内容的多行文本框等。然后为了能够实现e-mail的发送和设置,我们设计一个smtpmail类,它封装了与邮件服务器之间的socket 通信操作,以及smtp 命令的发送和响应信息的接收。

  编程技巧说明

  1.设置窗体和组件

  我们设计了一个mailsendframe()类继承frame 对象,作为容纳组件的主窗体。main()函数实现将窗体启动时置于屏幕的正中央,窗口定义代码如下:

public static void main(string[] args) {
mailsendframe mailsendframe = new mailsendframe();
dimension screensize = toolkit.getdefaulttoolkit().getscreensize();
dimension framesize = mailsendframe.getsize();
if (framesize.height > screensize.height) {
framesize.height = screensize.height;
}
if (framesize.width > screensize.width) {
framesize.width = screensize.width;
}
mailsendframe.setlocation((screensize.width - framesize.width) / 2,
(screensize.height - framesize.height) / 2);
mailsendframe.setvisible(true);
mailsendframe.show();
}

  在main()函数中,首先利用代表系统信息的toolkit对象得到当前系统中设置的屏幕分辨率,并且用分辨率和窗体的大小作比较,然后,调用mailsendframe的setlocation()方法设置窗体的左上角坐标,使窗体的中心和屏幕的中心正好重合,从而将窗体居中。

//组件实例变量的定义
panel panelmain = new panel();
panel panelup = new panel();
panel panel3 = new panel();
panel panel4 = new panel();
panel panel6 = new panel();
panel panel7 = new panel();
textfield txtserver = new textfield();
textfield txtto = new textfield();
textfield txtfrom = new textfield();
textfield txtsubject = new textfield();
panel panel8 = new panel();
label lblfile = new label();
button cmdbrowse = new button();
panel paneldown = new panel();
textarea txtmail = new textarea();
panel panel10 = new panel();
button cmdsend = new button();
button cmdexit = new button();
.......
.......
panelmain.add(panelup, null);
panelup.add(panel3, null);
panel3.add(new label("发信服务器:"), null);
panel3.add(txtserver, null);
panelup.add(panel4, null);
panel4.add(new label("收件人:"), null);
panel4.add(txtto, null);
panelup.add(panel6, null);
panelup.add(panel7, null);
panel7.add(new label("主题:"), null);
panel7.add(txtsubject, null);
panel6.add(new label("发件人:"), null);
panel6.add(txtfrom, null);
panelup.add(panel8, null);
panel8.add(new label("附件: "), null);
panel8.add(lblfile, null);
panel8.add(cmdbrowse, null);
panelmain.add(paneldown, null);
paneldown.add(txtmail, borderlayout.center);
paneldown.add(panel10, borderlayout.south);
panel10.add(cmdsend, null);
panel10.add(cmdexit, null);
paneldown.add(new label(" "), borderlayout.east);
paneldown.add(new label(" "), borderlayout.west);
........
........

  窗体组件的定义都是在init()方法中完成,设置好收件人、发信人和主题组件的单行文本框,书写邮件内容的多行文本框,以及附件中的浏览按钮、发送和退出按钮。

  2.窗体中的事件处理

  事件处理也是在init()方法中完成。选取附件文件的“浏览”按钮的事件处理,在单击该按钮时,打开一个openfiledialog 文件对话框,读取用户所选取的文件名。打开文件对话框的“浏览”按钮的代码如下:

private filedialog openfiledialog= new filedialog(this,"打开文件",filedialog.load);
public mailsendframe() {
try {
init();
}
catch(exception e) {
e.printstacktrace();
}
}
......
......

  单击“发送”按钮的事件处理,实现用户填写邮件信息的收集和邮件的发送操作。“发送”按钮的代码如下:

cmdsend.addactionlistener(new java.awt.event.actionlistener() {
public void actionperformed(actionevent e) {
cmdsend_actionperformed(e);
}
}

  实现cmdsend_actionperformed()方法如下:

void cmdsend_actionperformed(actionevent e) {
mailsender.setfrom(txtfrom.gettext().trim());
mailsender.setto(txtto.gettext().trim());
mailsender.addheader("subject",txtsubject.gettext().trim()) ;
mailsender.adddata(txtmail.gettext()) ;
if(!lblfile.gettext().trim().equals("") )
mailsender.addattachment(lblfile.gettext().trim());
mailsender.open(txtserver.gettext().trim(),25);
mailsender.transmit();
mailsender.close();
}

  单击“退出”按钮的事件处理,实现程序的退出和窗体的关闭。“退出”按钮和侦听器的程序代码如下:

cmdexit.addactionlistener(new java.awt.event.actionlistener() {
public void actionperformed(actionevent e) {
cmdexit_actionperformed(e);
}
}
this.addwindowlistener(new java.awt.event.windowadapter() {
public void windowclosing(windowevent e) {
this_windowclosing(e);
}
}

  上面程序分别为退出和窗体注册事件的侦听器或适配器,它们处理各自的交互动作。实现cmdexit_actionperformed()和this_windowclosing()方法如下:

void cmdexit_actionperformed(actionevent e) {
system.exit(0);
}
void this_windowclosing(windowevent e) {
system.exit(0);
}

  3.smtpmail 类的实现

  采用open()方法,建立与邮件服务器之间的tcp/ip 连接,创建套接字,并且得到发送命令所用的输出流send 和接收服务器相应所用的输入流rev。open()方法的代码如下:

public int open(string servername, int port){
try{
mailsocket = new socket(servername, port);
send = new printwriter(mailsocket.getoutputstream(), true);
recv = new bufferedreader(new inputstreamreader(mailsocket.getinputstream()));
string s1 = recv.readline();
char c = s1.charat(0);
if((c == '4') | (c == '5'))
return 0;
}
catch(exception e){
return 0;
}
return 1;
}

  在smtpmail 类中,通过transmit()方法完成发送任务。transmit()方法的代码如下:

public int transmit(){
boolean flag = true;
//发送helo 命令
if(domain.length() != 0){
int i = sendstring("helo " + domain);
if(i != 1)
return 0;
}
//发送mail from 命令(发件人)
if(from.length() != 0){
int j = sendstring("mail from:" + from);
if(j != 1)
return 0;
}
//发送rcpt to 命令(收件人)
if(to.length() != 0){
int k = sendstring("rcpt to:" + to);
if(k != 1)
return 0;
}
//发送邮件正文(data 命令)
if(sendstring("data") != 1)
return 0;
//发送邮件头信息
for(int l = 0; l < x_set.size(); l += 2){
string s = (string)x_set.elementat(l);
send.println(s + ": " + x_set.elementat(l + 1));
}
//发送时间及相关内容格式说明
if(x_set.indexof("date") < 0)
send.println("date: " + (new date()).tostring());
........
........

  使用sendstring()方法来发送字符串命令,并且接收邮件服务器的响应信息,判断命令是否被接收。返回1表示命令被拒绝执行,返回0表示命令被接受。sendstring()方法的代码如下:

private int sendstring(string s){
string s1 = "";
try{
send.println(s);
s1 = recv.readline();
}
catch(exception e){
system.out.print(s1);
return 0;
}
if(s1.length() == 0)
return 0;
char c = s1.charat(0);
return !((c == '4') | (c == '5')) ? 1 : 0;
}

  使用close()方法来关闭与服务器之间的套接字连接。该方法发送“quit”命令,收到响应消息后,才真正关闭连接。close()方法的代码如下:

public int close(){
int i = 0;
try{
i += sendstring("quit");
mailsocket.close();
}
catch(exception e){
return 0;
}
return i == 0 ? 1 : 0;
}

  mailsendframe.java源程序代码如下:

import java.awt.*;
import java.awt.event.*;
public class mailsendframe extends frame {
smtpmail mailsender=new smtpmail();
panel panelmain = new panel();
panel panelup = new panel();
panel panel3 = new panel();
panel panel4 = new panel();
panel panel6 = new panel();
panel panel7 = new panel();
textfield txtserver = new textfield();
textfield txtto = new textfield();
textfield txtfrom = new textfield();
textfield txtsubject = new textfield();
panel panel8 = new panel();
label lblfile = new label();
button cmdbrowse = new button();
panel paneldown = new panel();
textarea txtmail = new textarea();
panel panel10 = new panel();
button cmdsend = new button();
button cmdexit = new button();
private filedialog openfiledialog
= new filedialog(this,"打开文件",filedialog.load);
public mailsendframe() {
try {
init();
}
catch(exception e) {
e.printstacktrace();
}
}
public static void main(string[] args) {
mailsendframe mailsendframe = new mailsendframe();
dimension screensize = toolkit.getdefaulttoolkit().getscreensize();
dimension framesize = mailsendframe.getsize();
if (framesize.height > screensize.height) {
framesize.height = screensize.height;
}
if (framesize.width > screensize.width) {
framesize.width = screensize.width;
}
mailsendframe.setlocation((screensize.width - framesize.width) / 2,
(screensize.height - framesize.height) / 2);
mailsendframe.setvisible(true);
mailsendframe.show();
}
private void init() throws exception {
this.setlayout(new borderlayout());
panelmain.setlayout(new gridlayout(2,1));
panelup.setlayout(new gridlayout(6,1));
panel3.setlayout(new flowlayout());
this.setvisible(true);
.......
.......
//smtpmail.java 的源代码
import java.io.*;
import java.net.socket;
import java.util.*;
public class smtpmail{
private boolean sendconf=false;
public static final int ok = 1;
public static final int error = 0;
private static final string text = "1";
private static final string tfile = "2";
private static final string bfile = "3";
private static final string cpr = "java 1.0";
private static final string mailer = "x-mailer";
private static final int buffer_size = 48;
private string delimeter;
private string separator;
private static final int how_long = 6;
private static final char smtp_error_code1 = 52;
private static final char smtp_error_code2 = 53;
private static final int fillchar = 61;
private static final string cvt =
"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789+/";
private socket mailsocket;
private bufferedreader recv;
private printwriter send;
private string from;
private string to;
private string domain;
private vector x_set;
private vector body;
private vector attach;
public smtpmail(){
delimeter = "";
separator = "";
mailsocket = null;
recv = null;
send = null;
from = "";
to = "";
domain = "";
x_set = new vector();
body = new vector();
attach = new vector();
delimeter = getid();
separator = system.getproperty("file.separator");
}
.........
.........

扫描关注微信公众号