Реализация на стандартен протокол - SMTP

Simple Mail Transfer Protocol (SMTP) представлява Интернет стандарт за предаване на email съобщения. Първоначално описан от  RFC 821 ( 1982 г.), по-късно е разширен и допълнен от  Extended SMTP - RFC 5321, който се използва повсеместно понастоящем.

SMTP е използван от mail сървъри и агенти за изпращане и получаване  на съобщения. На потребителско ниво апликациите използват  SMTP само за изпращане на съобщения към обслужващ сървър за relaying ( препредаване ). За получаване на съобщения клиентските апликации използват протоколите IMAP или  POP3.

SMTP протокола използва за обмен на съобщения TCP порт  25. Клиентските приложения също могат да използват порт 25, но често предават изходящите  съобщения на порт 587.

SMTP командите са символни низове завършващи с <CRLF>.  Кодовете на командите са буквени и завършват с <SP> ако има пареметри или с <CRLF> ако няма.

Пример 1:Клиент за изпращане по SMTP протокол


Отваряне и затваряне

      Преди обмена на информацията се отваря трансмисионен канал за обмен на информацията за изпращача и сървъра.

      Използват се следните две команди за отваряне и затваряне - HELLO (HELO) и QUIT

         HELO <SP> <domain> <CRLF>

         QUIT <CRLF>

      С командата HELO изпращащата машина се идентифицира казвайки:
      "Hello, I am  <domain>".

 

Примерен диалог, който трябва да се води съгласно  RFC 821 (appendix F стр 50):

        
         R: 220 BBN-UNIX.ARPA Simple Mail Transfer Service Ready
S: HELO USC-ISIF.ARPA
R: 250 BBN-UNIX.ARPA

S: MAIL FROM:<Smith@USC-ISIF.ARPA>
R: 250 OK

S: RCPT TO:<Jones@BBN-UNIX.ARPA>
R: 250 OK

S: RCPT TO:<Green@BBN-UNIX.ARPA>
R: 550 No such user here

S: RCPT TO:<Brown@BBN-UNIX.ARPA>
R: 250 OK

S: DATA
R: 354 Start mail input; end with <CRLF>.<CRLF>

         S: Date: 23 Oct 81 11:22:33
         S: From: Smith@Alpha.ARPA
         S: To: Jones@Beta.ARPA,Green@Beta.ARPA,Brown@Beta.ARPA
         S: Subject: Mail System Problem

S: Blah blah blah...
S: ...etc. etc. etc.
S: .
R: 250 OK

S: QUIT
R: 221 BBN-UNIX.ARPA Service closing transmission channel

The mail from Smith has now been accepted for Jones and Brown.
Green did not have a mailbox at host BBN-UNIX.ARPA.
         

Всеки ред трябва да завършва с <CRLF> комбинация. В горния пример съобщението е прието за Jones и  Brown.  Green няма пощенска кутия в този сървър. Редовете:

         S: Date: 23 Oct 81 11:22:33
         S: From: Smith@Alpha.ARPA
         S: To: Jones@Beta.ARPA,Green@Beta.ARPA,Brown@Beta.ARPA
         S: Subject: Mail System Problem

задават "header" на съобщението и не са задължителни.


Клиентът:

import java.net.*;
import java.io.*;

public class MailSend{
private static String messageSys[]= new String[4],
messageData[]=new String[5],hostName=null,
sender = "<myName@myDomain.bg>";
private static InetAddress mServer= null;
public static void initStrings(){
messageSys[0]="HELO "+hostName+"\r\n";
messageSys[1]="MAIL FROM: "+sender+ "\r\n";
messageSys[2]="RCPT TO: ";
messageSys[3]="DATA\r\n";
messageData[0]="From: "+sender+"\r\n";
messageData[1]="To:";
messageData[2]="Subject: ";
messageData[3]= "";
messageData[4]=".\r\n";
}
public static void init(){
try{
mServer=InetAddress.getByName("myMailServer.bg");
hostName= InetAddress.getLocalHost().getHostName();
}catch(Exception e){System.out.println("Exception"+e); }
initStrings();
}
public static void putData(String arg[]){
messageSys[2]+="<"+arg[0]+">\r\n";
messageData[1]+=arg[0]+"\r\n";
messageData[2]+= arg[1]+"\r\n";
messageData[3]= arg[2]+"\r\n";

}
public static void send (){
try{ // или c timeout 10000 ms:
Socket s=null; // Socket s = new Socket();
s = new Socket(mServer,25); // s.connect(new InetSocketAddress(
// mserver,25),10000);
BufferedReader in = new BufferedReader(
new InputStreamReader(s.getInputStream()));
PrintWriter out = new PrintWriter(s.getOutputStream());
System.out.println(in.readLine());
for(int i=0; i<messageSys.length;i++){
out.print(messageSys[i]);
System.out.println(messageSys[i]);
out.flush();
System.out.println(in.readLine());
}
for(int i=0;i<messageData.length;i++){
out.print(messageData[i]);
System.out.println(messageData[i]);
out.flush();
}
System.out.println(in.readLine());
s.close();
}
catch(Exception e) {System.out.println(e); }
initStrings();
}
}

"myMailServer.bg" е машина с работещ mail transfer agent (MTA), например sendmail, за доставяне на пощата, който позволява препращането й (relay) от машината на клиента.

"
myName@myDomain.bg" е адресът на изпращача на mail-а, като адресът може да няма нищо общо с реалния изпращач на съобщението.  Някои сървъри , като антиспам мярка  са въвели изискването изпращача да е реално съществуващ  в таблицата  на mail клиентите им за да направят препращане (relay) на съобщението.


и съответния интерфейс:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class Gui{
JTextArea ta;
JTextField sb,to;
JLabel ls,lt;
JButton send;
Panel p= new Panel();
Gui(JFrame f){
ta = new JTextArea(10,20);
send = new JButton("send");
to = new JTextField("",20);
lt= new JLabel("To:");
sb = new JTextField("",20);
ls = new JLabel("Subject:");
send.addActionListener(new S());
p.add(lt);
p.add(to);
p.add(ls);
p.add(sb);
f.add(p,BorderLayout.NORTH);
f.add(ta, BorderLayout.CENTER);
f.add(send, BorderLayout.SOUTH);
MailSend.init();
}
class S implements ActionListener{
public void actionPerformed(ActionEvent e) {
String message[]= {to.getText(),sb.getText(),ta.getText()};
MailSend.putData(message);
MailSend.send();
}
}

public static void main(String args[]){
JFrame frame =new JFrame("Mail Sender");
Gui gui = new Gui(frame);
frame.setSize(600,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}

Задача: Въведете в интерфейса съобщения при неуспешно изпращане и прекратете диалога със сървъра в този случай.