Dịch vụ thư điện tử E-MAIL

Thư điện tử cho phép ta gửi các thông điệp, các tài liệu giữa các máy tính được kết nối mạng với nhau. Đây là một trong những ứng dụng phổ biến nhất trên mạng hiện nay. Rất nhiều dịch vụ E-mail được cung cấp miễn phí trên mạng như Microsoft Mail, Yahoo Mail, Netscape Mail, v.v. Các dịch vụ này cho phép ta chuyển tài liệu (thư) từ nơi này (máy này) đến nơi khác (máy khác) tương tự như việc gửi các bức thư qua bưu điện. Trong cách gửi truyền thống, ta phải cung cấp (viết trên phong bì) địa chỉ người gửi, người nhận sau đó bò thư vào hòm thư bưu điện. Đối với thư điện tù E-mail cũng tương tự. Máy chù cung cấp địa chỉ người gừi, ta cần ghi địa chì E-mail của người nhận. Dịch vụ E-mail sẽ chuyển thư gửi đi đến máy chủ hay Mail Server theo địa chì người nhận. Mail Server nơi nhận sẽ đặt bức thư nhận được vào hộp thư (Mail Box) trên máy chù nơi nhận (dưới dạng hệ thống tệp hay một CSDL). Người nhận muốn đọc thư phải đăng phập vào hòm thư của mình để đọc những bức thư từ những nơi khác gửi tới.

Dịch vụ E-mail rất đa dạng, nhưng chù yếu tập trung vào việc thiết lập:

  • Mail Server: Chương trình phía máy chù để nhận, phân phối, gùi thư đến các máy khác. Mail Server thực ra là một chưcmg trình mỡ socket để lắng nghe các yêu cẩu (gửi) từ các máy khác. Chính vì vậy, trước khi gửi hay nhận thư, ta phải biết rõ địa chì IP của Mail Server. Địa chi này thường được gọi là host mail. Các chương trình như Email, Daemon, Send Mail, Mail Exchange, v. là các Mail Server.
  • Mail Client: Chương trình hoạt động phía mảy khách, cho phép người dùng đăng nhập vào hộp thư của mình để đọc, viết và gửi thư cho người khác (ớ máy khác). Cỏ những chương trình Mail Client rất phổ biến như Outlook Express, Netscape Communicator. Nếu chương trình này được viết dưới dạng giao diện Web sẽ được gọi là Web Mail. Thật ra, Web Mail tương tác khó khăn hơn các ứng dụng Mail Client vỉ nó phải dựa vào Web Server để đọc và gửi đến Mail Server. Tuy nhiên, ưu điểm lớn nhất của Web Mail là ta có thể truy cập vào hòm thư của mình ở mọi nơi, mọi lúc, bất cứ khi nào kết nối được vào Ví dụ Hot Mail và Yahoo Mail là hai Web Mail được sử dụng rộng rãi hiện nay.
  • Giao thứcE-mail SMTP: Hiện nay người ta thường dùng giao thức chuyển thư điện tử SMTP để gửi E-mail. Chương trình chù tiếp nhận thư điện tử theo giao thức này được gọi là SMTP Server, còn chương trình khách sừ dụng nó nhận thư được gọi là SMTP Client.
  • Giao thức lưu trữ và nhận thư\ Khi Mail Server nhận thư, nó phải tổ chức lưu trữ thư theo một cách nào đó để các chương trinh khách dễ dàng truy cập và tải được thư về. Hiện nay POP3 và IMAP là hai giao thức lưu trữ và lấy thư từ hộp thư khá phổ biến. Các chương trình Mail Client thường sử dụng POP3 để lấy thư từ Mail Server và hiến thị chúng ở mảy khách.

1. Định dạng thư điện tử

Trước khi bắt tay vào việc xây dựng Java để gửi, nhận thư điện tử, ta cũng nên tìm hiểu về định dạng chuẩn của thư điện tử.

Mặc dù không bắt buộc, nhưng để mọi chương trình khách có thể dễ dàng hiển thị nội dung những bức thư nhạn được thì cẩu trúc của chúng cũng nên theo một khuôn dạng nhất định. Theo định dạng chuẩn RFC MIME, nội dung cùa mỗi bức thư điện tử gồm các phần: phần đầu (Header Mail), phần nội dung thư (Body Mail) và phần đính kèm (Mail Attachment) chứa nhiều loại tệp dữ liệu: hình ảnh, âm thanh, hay các loại tài liệu khác, v.v.

Phần đầu thư cần ghi rõ:

From:

Date :

To:

Subject :

Dựa vào những qui định chuẩn, người nhận biết được thư ai gừi, ngày viết, gừi cho ai và chù để chính cùa bức thư là gì.

2. Gửi thư điện tử

Trong nhiều trường hợp, chúng ta muốn tự gửi đi một mẩu tin mà không cằn sử dụng những dịch vụ E-mail như trên thỉ phải làm như thế nào?

Để gửi E-mail, ta có thể sử dụng kết nối Socket thông qua cổng 25 với giao thức SMTP. SMTP là giao thức vận chuyển mail đom giản tạo ra format cho thư điện tử.

Ví dụ 3.9. Một chưomg trình gừi thư đơn giản.

Như yêu cầu ờ hình 3.9, sau khi điền các thông tin về địa chi người gửi, người nhận, SMTP Server, ta viết thư (ờ vùng văn bản ờ trên), sau đó nhấn nút “Send” để gửi thư. Trong vùng văn bản ờ dưới sẽ hiển thị các câu lệnh gùi đến cho SMTP Server và sự trả lời khi nó nhận được nếu kết nối thành công, ngược lại sẽ thông báo lỗi.

I

// MailTest.java: Chương trình gửi thư đơn giản.

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import j ava.io.*;

import java.net.*;

import j avax.swing.*;

 

public class MailTest{

public static void main(String[] args){

JFrame fr = new MailTestFrame(); fr.show();

}

}

class MailTestFrame extends JFrame implements ActionListener{ public MailTestFrame(){ setTitle(“Mail Test”); setSize(300, 300);

addWindowListener(new WindowAdapter(){ public void windowclosing(WindowEvent e){

System, exit(0);

}

}) ;

getContentPane().setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weightx = 0; gbc.weighty = 0;

gbc.weightx = 0;

add(new JLabel(“From: “), gbc, 0, 0, 1, 1);

gbc.weightx = 100;

from = new JTextField(20);

add(from, gbc, 1, 0, 1, 1);

gbc.weightx = 0;

add(new JLabel(“To: “), gbc, 0, 1, 1, 1);

gbc.weightx = 100;

to = new JTextField(20);

add (to, gbc, 1, 1, 1, 1);

gbc.weightx = 0;

add(new JLabel(“SMTP server: “), gbc, 0, 2, 1, 1);

gbc.weightx = 100;

smtpServer = new JTextField(20);

add(smtpServer, gbc, 1, 2, 1, 1) ;

gbc.fill = GridBagConstraints.BOTH; gbc.weighty = 100; message = new JTextAreaO;

add(new JScrollPane(message) , gbc, 0, 3, 2, 1) ; response = new JTextAreaO;

add(new JScroll.Pane(response) , gbc, 0, 4, 2, 1); gbc.weighty = 0;

JButton sendButton = new JButton(“Send”) ; sendButton.addActionListener(this);

JPanel buttonPanel = new JPanel(); buttonPanel.add(sendButton); add(but.tonPanel, gbc, 0, 5, 2, 1) ;

}

private void add(Component c, GridBagConstraints gbc, int X, i.nt y, int w, int h) ( gbc.gridx = x; gbc.aridy = y; gbc.gridwidth = w; gbc.gridheight = h; getContentPane().add(c, gbc);

public void actionPerformed(ActionEvent e){

SwingUtilitres.invokeLater(new Runnable(){ public void run(){ sendMail();

});

public void sendMail(){ try{

Socket s = new Socket(smtpServer.getText(), 25); out = new PrintWriter(s.getOutputStream()); in = new BufferedReader(new

Input St reamReader (s. getlnputStream () ) ) ; String hostName =

InetAddress. getLocalHost () . getHostName () ; send(null);

send(“Hello ” + hostName); send(“RCPT to: ” + to.getText()); send(“Data”);

out.println(message.getText()); send(“.”); s.close();

}catch(IOException e){

response.append(“Error: ” + e);

)

}

public void send(String s) throws IOException{ if(s != null){

response.append(s + ”\n”); out.println(s); out.flush();

}

String line;

if((line = in.readLine()) != null) response.append(line + “\n”);

}

private BufferedReader in; private PrintWriter out; private JTextField from, to, smtpServer; private JTextArea message, response;

 

3. Kết nối theo bộ định vị tài nguyên URL để tìm tin

Nếu ta muốn phát triển chương trình ứng dụng, trong đó có dịch vụ E-mail riêng thì chắc chẳn ta phải sử dụng thư viện ở mức cao hơn, bao gồm cả các giao thức chi tiết trong đó. Sun Microsoft đã phát triển JavaMail API như là mở rộng chuẩn nền của Java. Trong JavaMa i 1 API, ta chỉ cần gọi

Transport.send(message)

để chuyển một thông điệp message đi. Thư viện này quan tâm đầy đù đến giao thức truyền tin, vấn đề nhiều người nhận, việc xử lý phần đính kèm, v.v.

Vấn đề đặt ra ờ đây là truy tìm các thông tin từ xa như thế nào?

Trong Java có hai lớp hỗ trợ để truy tìm thông tin từ xa, đỏ là URL và URLConnection. Việc tạo ‘ra một đối tượng để định vị tài nguyên có thể thục hiện nhu sau:

URL url = new URL(protocol:resource);

Trong đó, protocol là giao thức, có thể là HTTP hoặc FTP (Java 2SDK hỗ trợ cả hai), còn resource là địa chỉ nơi cần mở để trao đổi tin. Sau đó ta có thể tạo ra vùng đệm để đọc từng dòng tin và xử lý chúng.

Nếu ta chi cần biết về nội dung tin chứa ở một tài nguyên xác định thì chì cần sử dụng

lớp URL. Ví dụ,

URL url = n&v

URL(http://j ava .sun ,ccm/j 2se/1.4.2/docs/guide/rmi/getst art.doc.html);

Inputstream uin = url.opentstream();

BufferedReader in = new

BufferedReader (new InputStreamReader (uin) ) ;■

String liner-

while ((line in.readLine())              1= null){

process line; // Xừ lý từng dòng

}

Ở mục 3.5 ta đã nêu cách sử dụng URL đế truy tìm tin từ các nguồn từ xa.

Song, nếu ta muốn biết thêm các thông tin khác, hoặc muốn điều khiển việc truy cập vào các tài nguyên của Web thì phải sử dụng lớp URLConnection. Khi làm việc với đối tượng của URLConnectíon, ta cần phải thực hiện theo các bước sau.

  1. Gọi openConnection () cùa URL để có được đối tượng URLConnection connect = url.openConnection();
  2. Sử dụng các phương thức sau để đặt lại chúng.

setDoInput{) setDoOutput() setlfModifiedsìnce() setưserCaches() setAllowUserInteraction() setRequestProperty()

3. Kết nối vói tài nguyên từ xa bằng cách gọi phương thức connect () . connection,connect();

4. Sau khi đã kết nối được với Server, ta có thể truy vấn theo những tiêu đề, từ khoá, v.v. Có hai phương thức giúp ta liệt kê được tất cả các trường tiêu đề.

getHeaderFieldKey () và getHeaderFíeld(). Ngoài ra ta có thể sử dụng những phương thức sau:

5. Cuối cùng là truy cập vào đối tượng ờ nơi cần tìm. Sử dụng phương thức getlnputStreamO để nhận được những luồng tin đọc được từ nguồn tài nguyên.

Chúng ta hãy tim hiểu chi tiết hơn một số phương thức nêu trên. Trước tiên là setDoĩnput () và setDoOutput (). Theo mặc định, mọi kết nối chỉ cho phép đọc tin từ Server và không cho phép ghi. Nếu ta muốn tạo ra một luồng dữ liệu gừi đến cho Web Server thi cần gọi

connection.setDoOutput(true);

Phương thức setlfModifiedSince () báo cho đối tượng cần thực hiện kết nối biết rằng chúng ta chì quan tâm đến dữ liệu đà được cập nhật lần cuối. setUserCaches (), setAllowUser Interaction (> chi sử dụng ờ trong các Applet. Phương thức setRequestProperty () cho phép đặt lại các đặc tính như tên gọi người sử dụng, mật khẩu, mẫu tài liệu, v.v.

Ví dụ 3.10. Chương trình kết nối với tài nguyên từ xa.

// URLConnection java import java.io.*; import j ava.net.*; import java.util.*;

public class URLConnectionTest {

public static void main(String[] args){ try {

String urlName; if (args.length > 0)

urlName = args[0];

else

urlName = “http://java.sun.com”;

URL url = new URL(urlName);

URLConnection connection = url.openConnection();

// Lấy tên người sử dụng, mật khẩu từ các tham số ưên dòng lệnh if(args.length > 2){

String username = argsflj;

String password = args[2];

String input = username +                    + password;

String encoding – base64Encode(input); connection.setRequeStProperty(“Authorization”,

“Basic ” + encoding);

}

connection.connect() ;

// In ra từ khoá và tiêu đề int n = 1;

String key;

while((key = connection.getHeaderFieldKey(n)) != null){ String value = connection.getHeaderField(n); System.out.println(key + ” + value);

n+ + ;

1

// In ra các tính chất cùa nội dung tin

System, out. println ( “——————————— “) ;

System.out.printIn(“getContentType: ” +
connection.getContentType());

System.out.printIn(“getContentLength: ” +
connection.getContentLength());

System.out.printIn(“getContentEncoding: ” +
connection.getContentEncoding());

System.out.println(“getDate: ” +
connection.getDate() ) ;

System.out.println(“getLastModified: ” +
connection.getLastModified());

BufferedReader in = new BufferedReader (new

InputStreamReader(connection.getInputstream()));

System.out.println(” ————— “) ;

// In ra 10 dòng đầu tiên String line; n = 1;

while((line = in.readLine()) != null && n <= 10){

System.out.printIn(line) ; n++;

}

if(line != null)System.out.println(“…”);

)catch (IOException e){

System.out.println(“Error: ” + e);

>

}

public static String base64Encode(String s){

ByteArrayOutputStream bOut = new ByteArrayOutputStream(); Base640utputstream out = new Base640utputstream(bout); try {

out .write (s . getBytes () ) out.flush();

}catch(IOException e){

>

return bout.toString();

)

}

// BASE64 mã 3 byte cho 4 ký tự. |11111122Ị22223333|33444444|. Mỗi tập gồm 6 bít // duợc mt hoá theo ánh xạ toBase64. Mỗi dòng in ra dàj nhất là 76 ký tự.

class Base640utputstream extends FilterOutputStream{

private int inbuf[] = new ínt[3];

public Base640utputStream(Outputstream out){ super (out);

}

public void write(int c) throws IOException{ inbuf[i] = c;

Í + + /

if(i == 3)(

super.write(toBase64[(inbuf[0] & OxFC) » 2]); super.write(toBase64t((inbuf[0] & 0x03) << 4) I ( (inbuf[1] & OxFO) » 4)]) ; super.write (toBase64(((inbuf[1] & OxOF) << 2) I ((inbuf[2] & OxCO) » 6)]); super.write(toBase64[inbuf[2] & 0x3F]); col += 4; i = 0;

if(col >= 76){

super.write(‘\n’); col = 0;

}

public void flush 0 throws IOException{ if (i == 1) {

super .write (toBase64 [ (inbuf [0] & C’xFC) super.write(toBase64f(inbuf[0] & 0x03) super.write(‘=’); super.write{‘=’);

}else{

super.write(toBase64t(inbuf[0] & OxFC) super.write(toBase64[((inbuf[0] & 0x03) ((inbuf[l] & OxFO) >> 4)]); super.write(toBase64[(inbuf[1] & OxOF) super.write(‘=’);

}

}

}