用Java实现SMTP服务器

2016-02-19 20:09 72 1 收藏

每个人都希望每天都是开心的,不要因为一些琐事扰乱了心情还,闲暇的时间怎么打发,关注图老师可以让你学习更多的好东西,下面为大家推荐用Java实现SMTP服务器,赶紧看过来吧!

【 tulaoshi.com - 编程语言 】


  
  电子邮件传递可以由多种协议来实现。目前,在Internet 网上最流行的三种电子邮件协议是SMTP、POP3 和 IMAP,下面分别简单介绍。
  
  ◆ SMTP 协议
  
   !-- frame contents --!-- /frame contents --   简单邮件传输协议(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");
  }
  .........
  .........
  

来源:http://www.tulaoshi.com/n/20160219/1622871.html

延伸阅读
阿里云服务器怎么用?   阿里云使用,第一步购买;第二步配置环境啊,那是个空主机,需要格式化安装软件,第三步上域名注册的地方解析域名把服务器ip弄过去,第四步,用工具连接服务器,把代码传上去(htdocs?) 首先,要感谢阿里云论坛,感谢朋友们对我的帮助,因为3天前,我还是一个对linux系统一无所知的人,在这个论坛,问了很多...
标签: Web开发
昨天一个朋友有个需求,是要通过WEB方式,修改IIS服务器上的时间,由于他的系统是ASP 3.0下开发的,所以本例子的代码是ASP的,不是ASP.NET,但是本人写这个文章是想抛砖引玉,毕竟编写程序关键的不是语言,更重要的是一种思想,把程序语言理解为一种工具,把编程思想理解为解决问题的思路和方法,那么编写出来的程序就是:利用“工具”按照...
一、引 言 ---- Windows Socket API是一套开放的、支持多种协议的Windows下的网络编程接口,它包 括一个标准的 Berkeley Socket功能调用的集合,以及为Windows所作的重要扩充。 Windows Socket经过不断完善并在众 多公司的全力支持下,已成为Windows网络编程 的事实上的标准。 ---- 本 文 将 在VC++ 5.0 环 境 下 介 绍 一个基于 Winsock ...
标签: Java JAVA基础
一、概述 编写安全的Internet应用并不是一件轻而易举的事情:只要看看各个专业公告板就可以找到连续不断的安全漏洞报告。你如何保证自己的Internet应用不象其他人的应用那样满是漏洞?你如何保证自己的名字不会出现在令人难堪的重大安全事故报道中? 如果你使用Java Servlet、JavaServer Pages(JSP)或者EJB,许...
标签: ASP
       ---- 音乐服务器(Music Server)是指一个提供音乐在线服务的服务器,它包括高端提供门户服务的网站、Web数据库和低端的操作平台、硬件设施。目前,在Internet和Intranet上有不少这样的站点,特别是在一些高速宽带的局域网中(如校园网),音乐服务器给上网的朋友提供了休闲娱乐的好去处,同时也给...

经验教程

723

收藏

72
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部