Thư điện tử đã có từ khi Internet mới bắt đầu phát triển. Nó là ứng dụng phổ biến nhất khi Internet còn trong giai đoạn sơ khai [Segaller 1998] và đã trở nên phức tạp hơn và mạnh mẽ hơn theo thời gian. Nó vẫn là một trong những ứng dụng quan trọng và được sử dụng nhiều nhất trên Internet.
Giống như thư truyền thống, email là một phương tiện giao tiếp không đồng bộ — người ta gửi và đọc thư khi thuận tiện cho mình, mà không cần phải phối hợp với lịch trình của người khác. Khác với thư truyền thống, email nhanh chóng, dễ phân phối và chi phí thấp. Email hiện đại có nhiều tính năng mạnh mẽ, bao gồm thư có tệp đính kèm, liên kết, văn bản định dạng HTML và ảnh nhúng.
Trong những bài viết sắp tới, chúng ta sẽ tìm hiểu về các giao thức ở tầng ứng dụng làm nền tảng cho email trên Internet. Nhưng trước khi đi sâu vào các giao thức này, chúng ta hãy nhìn qua một cái nhìn tổng quan về hệ thống thư điện tử trên Internet và các thành phần chính của nó.
Hình dưới trình bày cái nhìn tổng quan về hệ thống thư điện tử trên Internet. Qua sơ đồ này, ta thấy rằng nó có ba thành phần chính: tác nhân người dùng (user agent), máy chủ thư, và Simple Mail Transfer Protocol (SMTP). Ta sẽ mô tả từng thành phần này trong bối cảnh Alice gửi một tin nhắn email cho người nhận là Bob. Tác nhân người dùng cho phép người dùng đọc, trả lời, chuyển tiếp, lưu và soạn tin nhắn. Một số ví dụ về tác nhân người dùng cho email bao gồm Microsoft Outlook, Apple Mail, Gmail trên nền web, ứng dụng Gmail trên điện thoại thông minh, … Khi Alice hoàn thành soạn tin nhắn, tác nhân người dùng của cô ấy sẽ gửi tin nhắn đến máy chủ thư của cô ấy, nơi tin nhắn sẽ được đặt vào hàng đợi tin nhắn đi của máy chủ thư. Khi Bob muốn đọc tin nhắn, tác nhân người dùng của anh ấy sẽ truy xuất tin nhắn từ hộp thư của anh ấy trong máy chủ thư của mình.
Máy chủ thư là phần cốt lõi của hạ tầng email. Mỗi người nhận, như Bob, có một hộp thư được lưu trữ trong một trong các máy chủ thư. Hộp thư của Bob quản lý và duy trì các tin nhắn đã gửi đến anh ấy. Một tin nhắn thông thường bắt đầu hành trình của mình từ tác nhân người dùng của người gửi, sau đó di chuyển đến máy chủ thư của người gửi, rồi đến máy chủ thư của người nhận, nơi nó được lưu vào hộp thư của người nhận. Khi Bob muốn truy cập các tin nhắn trong hộp thư của mình, máy chủ thư chứa hộp thư của anh ấy sẽ xác thực Bob (với tên người dùng và mật khẩu). Máy chủ thư của Alice cũng phải xử lý các lỗi trong máy chủ thư của Bob. Nếu máy chủ của Alice không thể gửi thư đến máy chủ của Bob, máy chủ của Alice sẽ giữ tin nhắn trong hàng đợi tin nhắn và cố gắng gửi lại sau. Các lần thử lại thường được thực hiện sau mỗi 30 phút; nếu không thành công sau vài ngày, máy chủ sẽ xóa tin nhắn và thông báo cho người gửi (Alice) bằng một email.
SMTP là giao thức chính ở tầng ứng dụng cho email trên Internet. Nó sử dụng dịch vụ truyền dữ liệu tin cậy của TCP để chuyển thư từ máy chủ thư của người gửi đến máy chủ thư của người nhận. Như hầu hết các giao thức ở tầng ứng dụng, SMTP có hai phía: phía khách hàng, thực thi trên máy chủ thư của người gửi, và phía máy chủ, thực thi trên máy chủ thư của người nhận. Cả hai phía của SMTP đều chạy trên mọi máy chủ thư. Khi một máy chủ thư gửi thư cho các máy chủ thư khác, nó hoạt động như một SMTP client. Khi một máy chủ thư nhận thư từ các máy chủ thư khác, nó hoạt động như một máy chủ SMTP.
Simple Mail Transfer Protocol (SMTP)
SMTP, được định nghĩa trong RFC 5321, là cốt lõi của thư điện tử trên Internet. Như đã đề cập ở trên, SMTP chuyển các tin nhắn từ máy chủ thư của người gửi đến máy chủ thư của người nhận. SMTP có tuổi đời lâu hơn HTTP. (RFC SMTP ban đầu có từ năm 1982, và SMTP đã tồn tại trước đó rất lâu.) Mặc dù SMTP có nhiều đặc tính tuyệt vời, như được chứng minh qua sự phổ biến của nó trên Internet, nhưng nó vẫn là một công nghệ cũ với một số đặc điểm lỗi thời. Ví dụ, nó giới hạn phần thân (chứ không chỉ phần tiêu đề) của tất cả các tin nhắn thư điện tử ở dạng 7-bit ASCII đơn giản.
Điều này từng hợp lý vào những năm 1980 khi dung lượng truyền tải còn hạn chế và không ai gửi tệp đính kèm lớn hoặc tệp hình ảnh, âm thanh, video lớn qua email. Nhưng ngày nay, trong kỷ nguyên đa phương tiện, giới hạn 7-bit ASCII trở nên phiền toái — nó yêu cầu dữ liệu đa phương tiện nhị phân phải được mã hóa thành ASCII trước khi gửi qua SMTP; và sau đó dữ liệu ASCII tương ứng phải được giải mã lại thành nhị phân sau khi chuyển qua SMTP. Nhắc lại từ Mục 2.2 rằng HTTP không yêu cầu dữ liệu đa phương tiện phải được mã hóa thành ASCII trước khi chuyển.
Để minh họa hoạt động cơ bản của SMTP, giả sử Alice muốn gửi Bob một tin nhắn ASCII đơn giản.
- Alice kích hoạt user agent của cô ta để gửi email, cung cấp địa chỉ email của Bob (ví dụ: bob@someschool.edu), soạn tin nhắn, và yêu cầu user agent gửi tin nhắn đó.
- User agent của Alice gửi tin nhắn đến máy chủ thư của cô ta, đặt vào hàng đợi tin nhắn.
- Phía khách của SMTP, chạy trên máy chủ thư của Alice, thấy tin nhắn trong hàng đợi. Nó mở kết nối TCP đến một máy chủ SMTP, chạy trên máy chủ thư của Bob.
- Sau một số bước bắt tay SMTP ban đầu, phía khách của SMTP gửi tin nhắn của Alice vào kết nối TCP.
- Tại máy chủ thư của Bob, phía máy chủ của SMTP nhận tin nhắn. Máy chủ thư của Bob sau đó đặt tin nhắn vào hộp thư của Bob.
- Bob kích hoạt tác nhân người dùng của anh để đọc tin nhắn khi anh cảm thấy thuận tiện.
Điều quan trọng là phải lưu ý rằng SMTP thường không sử dụng các máy chủ thư trung gian để gửi thư, ngay cả khi hai máy chủ thư nằm ở hai đầu đối diện của thế giới. Nếu máy chủ của Alice ở Hồng Kông và máy chủ của Bob ở St. Louis, kết nối TCP là kết nối trực tiếp giữa các máy chủ Hồng Kông và St. Louis. Cụ thể, nếu máy chủ thư của Bob bị gián đoạn, tin nhắn vẫn sẽ nằm lại trong máy chủ thư của Alice và chờ một lần thử lại mới — tin nhắn không được chuyển đến một máy chủ thư trung gian nào.
Giờ hãy cùng xem xét kỹ hơn cách mà SMTP chuyển một tin nhắn từ máy chủ thư gửi sang máy chủ thư nhận. Chúng ta sẽ thấy rằng giao thức SMTP có nhiều điểm tương đồng với các giao thức được sử dụng trong giao tiếp trực tiếp giữa con người. Đầu tiên, phía khách của SMTP (chạy trên máy chủ thư gửi) yêu cầu TCP thiết lập một kết nối đến cổng 25 của phía máy chủ SMTP (chạy trên máy chủ thư nhận). Nếu máy chủ bị gián đoạn, phía khách sẽ thử lại sau. Khi kết nối này được thiết lập, máy chủ và khách sẽ thực hiện một số bước bắt tay ở tầng ứng dụng—giống như con người thường giới thiệu bản thân trước khi trao đổi thông tin với nhau, các khách hàng và máy chủ SMTP cũng giới thiệu bản thân trước khi truyền tải thông tin.
Trong giai đoạn bắt tay SMTP này, phía khách SMTP chỉ ra địa chỉ email của người gửi (người đã tạo ra tin nhắn) và địa chỉ email của người nhận. Sau khi phía khách và phía máy chủ đã giới thiệu bản thân, khách hàng sẽ gửi tin nhắn. SMTP có thể dựa vào dịch vụ truyền dữ liệu tin cậy của TCP để đảm bảo rằng tin nhắn sẽ đến máy chủ mà không có lỗi. Sau đó, phía khách sẽ lặp lại quá trình này qua kết nối TCP nếu nó còn các tin nhắn khác cần gửi đến máy chủ; nếu không, nó yêu cầu TCP đóng kết nối.
Tiếp theo, chúng ta sẽ xem xét một ví dụ về bản ghi chép tin nhắn trao đổi giữa một phía khách SMTP (C) và một phía máy chủ SMTP (S). Tên máy chủ của phía khách là crepes.fr và tên máy chủ của phía máy chủ là hamburger.edu. Các dòng văn bản ASCII có tiền tố “C:” là các dòng mà phía khách gửi vào cổng TCP của mình, và các dòng văn bản ASCII có tiền tố “S:” là các stream mà máy chủ gửi vào cổng TCP của mình. Bản ghi chép dưới đây bắt đầu ngay khi kết nối TCP được thiết lập.
S: 220 hamburger.edu
C: HELO crepes.fr
S: 250 Hello crepes.fr, pleased to meet you
C: MAIL FROM: <alice@crepes.fr>
S: 250 alice@crepes.fr ... Sender ok
C: RCPT TO: <bob@hamburger.edu>
S: 250 bob@hamburger.edu ... Recipient ok
C: DATA
S: 354 Enter mail, end with ”.” on a line by itself
C: Do you like ketchup?
C: How about pickles?
C: .
S: 250 Message accepted for delivery
C: QUIT
S: 221 hamburger.edu closing connection
Trong ví dụ trên, phía khách hàng gửi một tin nhắn (“Do you like ketchup? How about pickles?”) từ máy chủ thư crepes.fr đến máy chủ thư hamburger.edu. Trong quá trình đối thoại, phía khách đã thực hiện năm lệnh: HELO (viết tắt của “HELLO”), MAIL FROM, RCPT TO, DATA, và QUIT. Những lệnh này đều khá rõ ràng. Phía khách cũng gửi một dòng chứa một dấu chấm đơn, báo hiệu kết thúc của tin nhắn đối với máy chủ. (Trong ngôn ngữ ASCII, mỗi tin nhắn kết thúc với CRLF.CRLF, trong đó CR và LF lần lượt là ký tự “Carriage Return” và “Line Feed”.)
Máy chủ sẽ trả lời từng lệnh với một mã phản hồi và một giải thích bằng tiếng Anh (tùy chọn). Chúng ta cũng cần lưu ý rằng SMTP sử dụng kết nối bền vững: Nếu máy chủ thư gửi có nhiều tin nhắn cần gửi đến cùng một máy chủ thư nhận, nó có thể gửi tất cả các tin nhắn này qua cùng một kết nối TCP. Đối với mỗi tin nhắn, phía khách sẽ bắt đầu quy trình với MAIL FROM: crepes.fr, chỉ định kết thúc tin nhắn với một dấu chấm đơn, và chỉ thực hiện lệnh QUIT sau khi tất cả các tin nhắn đã được gửi.
Việc sử dụng Telnet để thực hiện một cuộc đối thoại trực tiếp với máy chủ SMTP là rất được khuyến khích. Để thực hiện điều này, bạn có thể sử dụng lệnh Telnet như sau:
telnet serverName 25
serverName là tên của máy chủ thư nội bộ (local mail server). Khi bạn thực hiện lệnh này, bạn chỉ đơn giản là thiết lập một kết nối TCP giữa máy chủ địa phương của bạn và máy chủ thư. Sau khi nhập dòng lệnh này, bạn sẽ ngay lập tức nhận được phản hồi 220 từ máy chủ.
Tiếp theo, ta thực hiện các lệnh SMTP như HELO, MAIL FROM, RCPT TO, DATA, CRLF.CRLF, và QUIT vào thời điểm thích hợp.
Định dạng thông điệp thư điện tử
Khi Alice viết một bức thư thông thường gửi qua bưu điện cho Bob, cô có thể bao gồm các thông tin tiêu đề phụ ở đầu bức thư, chẳng hạn như địa chỉ của Bob, địa chỉ trả lại của cô và ngày tháng. Tương tự, khi một tin nhắn email được gửi từ người này sang người khác, một tiêu đề chứa thông tin phụ sẽ xuất hiện trước phần nội dung của tin nhắn. Thông tin phụ này được chứa trong một loạt các dòng tiêu đề, được định nghĩa trong RFC 5322. Các dòng tiêu đề và phần nội dung của tin nhắn được phân cách bởi một dòng trống (tức là CRLF). RFC 5322 quy định định dạng chính xác cho các dòng tiêu đề của thư điện tử cũng như cách giải thích ngữ nghĩa của chúng.
Giống như với HTTP, mỗi dòng tiêu đề chứa văn bản có thể đọc được, bao gồm một từ khóa, sau đó là dấu hai chấm, rồi đến giá trị của từ khóa. Một số từ khóa là bắt buộc, trong khi những từ khóa khác là tùy chọn. Mỗi tiêu đề phải có dòng From: và To:; một tiêu đề cũng có thể bao gồm dòng Subject: cùng với các dòng tiêu đề tùy chọn khác. Điều quan trọng là lưu ý rằng các dòng tiêu đề này khác với các lệnh SMTP mà chúng ta đã nghiên cứu trong Mục 2.3.1 (dù chúng có chứa một số từ giống nhau như “from” và “to”). Các lệnh trong phần đó là một phần của giao thức bắt tay SMTP; các dòng tiêu đề được xem xét trong phần này là một phần của nội dung tin nhắn email.
Một tiêu đề tin nhắn điển hình trông như thế này:
From: alice@crepes.fr
To: bob@hamburger.edu
Subject: Searching for the meaning of life.
Sau tiêu đề tin nhắn, một dòng trống (CRLF) sẽ xuất hiện; rồi tiếp theo là nội dung của tin nhắn (ở định dạng ASCII).
Ta nên sử dụng Telnet để gửi một tin nhắn đến một máy chủ thư có chứa các dòng tiêu đề, bao gồm cả dòng tiêu đề Subject:. Để thực hiện điều này, ta có thể sử dụng lệnh:
telnet serverName 25
Giao thức truy cập mail
Khi SMTP chuyển tin nhắn từ máy chủ thư của Alice sang máy chủ thư của Bob, tin nhắn sẽ được đặt vào hộp thư của Bob. Vì Bob (người nhận) thực thi tác nhân người dùng (user agent) của mình trên máy chủ cục bộ (ví dụ: điện thoại thông minh hoặc PC), nên việc đặt một máy chủ thư trên máy chủ cục bộ của Bob là điều hợp lý. Với cách tiếp cận này, máy chủ thư của Alice sẽ trực tiếp giao tiếp với PC của Bob. Tuy nhiên, có một vấn đề với cách tiếp cận này. Như đã đề cập trước đó, một máy chủ thư quản lý các hộp thư và chạy cả phía client và server của SMTP. Nếu máy chủ thư của Bob nằm trên máy chủ cục bộ của anh ấy, thì máy chủ của Bob sẽ phải luôn bật và kết nối với Internet để nhận thư mới, vì thư có thể đến vào bất kỳ lúc nào. Điều này là không thực tế đối với nhiều người dùng Internet. Thay vào đó, một người dùng điển hình sẽ chạy một tác nhân người dùng trên máy chủ cục bộ nhưng truy cập hộp thư của mình được lưu trữ trên một máy chủ thư chia sẻ luôn bật. Máy chủ thư này được chia sẻ với các người dùng khác.
Bây giờ, chúng ta hãy xem xét con đường mà một tin nhắn email sẽ đi khi nó được gửi từ Alice đến Bob. Chúng ta vừa mới học được rằng vào một thời điểm nào đó trên con đường, tin nhắn email cần phải được lưu trữ vào máy chủ thư của Bob. Điều này có thể đơn giản được thực hiện bằng cách để tác nhân người dùng của Alice gửi tin nhắn trực tiếp đến máy chủ thư của Bob. Tuy nhiên, thông thường, tác nhân người dùng của người gửi không giao tiếp trực tiếp với máy chủ thư của người nhận. Thay vào đó, như thể hiện trong hình dưới, tác nhân người dùng của Alice sử dụng SMTP hoặc HTTP để chuyển tin nhắn email vào máy chủ thư của cô, sau đó máy chủ thư của Alice sử dụng SMTP (như một client SMTP) để chuyển tiếp tin nhắn email đến máy chủ thư của Bob. Tại sao lại là quy trình hai bước? Chủ yếu là vì nếu không có sự chuyển tiếp qua máy chủ thư của Alice, tác nhân người dùng của Alice sẽ không có cách nào xử lý khi máy chủ thư đích không thể tiếp cận được. Bằng cách để Alice đầu tiên lưu trữ email trong máy chủ thư của mình, máy chủ thư của Alice có thể thử gửi tin nhắn đến máy chủ thư của Bob nhiều lần, ví dụ như mỗi 30 phút, cho đến khi máy chủ thư của Bob hoạt động trở lại. (Và nếu máy chủ thư của Alice bị lỗi, cô ấy có thể yêu cầu trợ giúp từ người quản trị hệ thống)
Tuy nhiên, vẫn còn một vấn đề chưa được giải quyết! Làm thế nào để một người nhận như Bob, chạy tác nhân người dùng trên máy chủ cục bộ của mình, lấy được tin nhắn, vốn đang nằm trong máy chủ thư? Lưu ý rằng tác nhân người dùng của Bob không thể sử dụng SMTP để lấy tin nhắn vì việc lấy tin nhắn là một hoạt động pull, trong khi SMTP là một giao thức push. Ngày nay, có hai cách phổ biến để Bob truy xuất email từ máy chủ thư. Nếu Bob đang sử dụng email web-based hoặc một ứng dụng điện thoại thông minh (như Gmail), thì tác nhân người dùng sẽ sử dụng HTTP để truy xuất email của Bob. Trường hợp này yêu cầu máy chủ thư của Bob phải có cả giao diện HTTP và giao diện SMTP (để giao tiếp với máy chủ thư của Alice). Phương pháp thay thế, thường được sử dụng với các ứng dụng email như Microsoft Outlook, là sử dụng Giao thức Truy cập Email qua Internet (IMAP) được định nghĩa trong RFC 3501. Cả hai phương pháp HTTP và IMAP đều cho phép Bob quản lý các thư mục được duy trì trong máy chủ thư của Bob. Bob có thể di chuyển tin nhắn vào các thư mục mà anh tạo, xóa tin nhắn, đánh dấu tin nhắn là quan trọng, và nhiều hành động khác.