- Sản phẩm & Dịch vụSản phẩm & Dịch vụ
- Giải phápGiải pháp
- Bảng giáBảng giá
- Công tyCông ty
- Tài liệuTài liệu
vi
vi
Chuyên mục với các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.
Web Developer
I’m passionate about web development and sharing my insights through articles, with over 8 years of experience. I hope these sharings inspire you and help build a strong web development community. @#@ Tôi đam mê phát triển web và chia sẻ những hiểu biết của mình thông qua các bài viết, với hơn 8 năm kinh nghiệm. Tôi hy vọng những chia sẻ này sẽ truyền cảm hứng cho các bạn và giúp xây dựng một cộng đồng phát triển web mạnh mẽ.
Thảo luận (0)
Đăng nhập để thảo luận
Hôm nay chúng ta sẽ tìm hiểu về một ví dụ dùng JavaMail để gửi email trong các chương trình Java. Đây là một trong những tác vụ phổ biến trong các ứng dụng thực tế, cũng là lý do Java cung cấp một API mạnh mẽ như vậy để chúng ta có thể sử dụng để gửi email thông qua máy chủ SMTP. JavaMail hỗ trợ cả TLS và SSL trong việc xác thực email.

Hôm nay, chúng ta sẽ học cách sử dụng JavaMail API để gửi email qua SMTP server trong cả trường hợp không cần xác thực và xác thực với TLS và SSL, cũng như cách gửi file đính kèm và đính kèm hình ảnh để sử dụng trong nội dung email.
Đối với xác thực TLS và SSL, ta sử dụng GMail SMTP server vì nó hỗ trợ cả hai giao thức. Bạn cũng có thể chọn sử dụng một máy chủ mailJava tùy theo nhu cầu của mình.
JavaMail API không phải là một phần của JDK chuẩn, vì vậy bạn sẽ cần tải nó từ trang web chính thức. Hãy tải xuống phiên bản mới nhất của bản reference implementation (triển khai tham chiếu) từ đó và đưa nó vào build path của dự án. Tên file jar sẽ là javax.mail.jar. Nếu dự án của bạn dùng Maven, chỉ cần thêm dependency dưới đây vào nó:
dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.5.5</version> </dependency>
Để gửi email ta cần thực hiện các bước sau:
javax.mail.Session .javax.mail.internet.MimeMessage. Chúng ta cần thiết lập các thuộc tính khác nhau cho đối tượng này, chẳng hạn như địa chỉ email người nhận, chủ đề email, email trả lời (Reply-To), nội dung email, file đính kèm, v.v.javax.mail.Transport để gửi email.Logic để tạo session khác nhau tùy thuộc vào loại máy chủ SMTP. Ví dụ, nếu nó không yêu cầu bất kỳ xác thực nào, chúng ta có thể tạo đối tượng Session với một vài thuộc tính đơn giản. Trong khi nếu nó yêu cầu xác thực TLS hoặc SSL, thì logic tạo Session sẽ khác.
Vì vậy, ở bài này ta sẽ tạo một utility class với một số phương thức tiện ích để gửi email, và sau đó ta sẽ sử dụng chúng với các SMTP server khác nhau.
Class EmailUtil của chúng ta vốn có một phương thức duy nhất để gửi email như bên dưới. Nó yêu cầu javax.mail.Session và một số trường bắt buộc khác làm tham số.
Để giữ cho nó đơn giản, một số tham số được gán cố định. Nhưng bạn có thể tùy ý mở rộng phương thức này để truyền chúng vào hoặc đọc chúng từ các file config.
package com.journaldev.mail;import java.io.UnsupportedEncodingException; import java.util.Date;
import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.mail.BodyPart; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart;
public class EmailUtil {
/** * Utility method to send simple HTML email * @param session * @param toEmail * @param subject * @param body */ public static void sendEmail(Session session, String toEmail, String subject, String body){ try { MimeMessage msg = new MimeMessage(session); //set message headers msg.addHeader("Content-type", "text/HTML; charset=UTF-8"); msg.addHeader("format", "flowed"); msg.addHeader("Content-Transfer-Encoding", "8bit"); msg.setFrom(new InternetAddress("no_reply@example.com", "NoReply-JD")); msg.setReplyTo(InternetAddress.parse("no_reply@example.com", false)); msg.setSubject(subject, "UTF-8"); msg.setText(body, "UTF-8"); msg.setSentDate(new Date()); msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false)); System.out.println("Message is ready"); Transport.send(msg); System.out.println("EMail Sent Successfully!!"); } catch (Exception e) { e.printStackTrace(); } }}
Lưu ý rằng ta đang thiết lập một số header property (thuộc tính tiêu đề) trong MimeMessage. Chúng được các email client sử dụng để render và hiển thị email một cách chính xác. Phần còn lại của chương trình rất đơn giản và dễ hiểu.
Bây giờ, chúng ta hãy tạo chương trình để gửi email không cần xác thực.
package com.journaldev.mail;import java.util.Properties;
import javax.mail.Session;
public class SimpleEmail {
public static void main(String[] args) { System.out.println("SimpleEmail Start"); String smtpHostServer = "smtp.example.com"; String emailID = "email_me@example.com"; Properties props = System.getProperties(); props.put("mail.smtp.host", smtpHostServer); Session session = Session.getInstance(props, null); EmailUtil.sendEmail(session, emailID,"SimpleEmail Testing Subject", "SimpleEmail Testing Body"); }}
Lưu ý rằng ta đang sử dụng Session.getInstance() để lấy đối tượng Session bằng cách truyền vào đối tượng Properties. Chúng ta cần đặt thuộc tính mail.smtp.host với host của SMTP server. Nếu SMTP server không chạy trên port mặc định (25), thì bạn cũng sẽ cần đặt thuộc tính mail.smtp.port.
Chỉ cần chạy chương trình trên với SMTP server không yêu cầu xác thực của bạn và đặt ID email người nhận là ID email của chính bạn, bạn sẽ nhận được email ngay lập tức. Chương trình này siêu đơn giản, dễ hiểu và hoạt động tốt. Nhưng trong thực tế, hầu hết các SMTP server đều sử dụng một số loại xác thực như TLS hoặc SSL. Vì vậy, bây giờ chúng ta sẽ xem cách tạo đối tượng Session cho các giao thức này.
package com.journaldev.mail;import java.util.Properties;
import javax.mail.Authenticator; import javax.mail.PasswordAuthentication; import javax.mail.Session;
public class TLSEmail {
/** Outgoing Mail (SMTP) Server requires TLS or SSL: smtp.gmail.com (use authentication) Use Authentication: Yes Port for TLS/STARTTLS: 587 */ public static void main(String[] args) { final String fromEmail = "myemailid@gmail.com"; //requires valid gmail id final String password = "mypassword"; // correct password for gmail id final String toEmail = "myemail@yahoo.com"; // can be any email id System.out.println("TLSEmail Start"); Properties props = new Properties(); props.put("mail.smtp.host", "smtp.gmail.com"); //SMTP Host props.put("mail.smtp.port", "587"); //TLS Port props.put("mail.smtp.auth", "true"); //enable authentication props.put("mail.smtp.starttls.enable", "true"); //enable STARTTLS //create Authenticator object to pass in Session.getInstance argument Authenticator auth = new Authenticator() { //override the getPasswordAuthentication method protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(fromEmail, password); } }; Session session = Session.getInstance(props, auth); EmailUtil.sendEmail(session, toEmail,"TLSEmail Testing Subject", "TLSEmail Testing Body"); }}
Vì ta đang sử dụng máy chủ SMTP của GMail mà ai cũng có thể truy cập được, bạn có thể đặt các biến chính xác trong chương trình trên và tự mình chạy thử.
package com.journaldev.mail;import java.util.Properties;
import javax.mail.Authenticator; import javax.mail.PasswordAuthentication; import javax.mail.Session;
public class SSLEmail {
/** Outgoing Mail (SMTP) Server requires TLS or SSL: smtp.gmail.com (use authentication) Use Authentication: Yes Port for SSL: 465 */ public static void main(String[] args) { final String fromEmail = "myemailid@gmail.com"; //requires valid gmail id final String password = "mypassword"; // correct password for gmail id final String toEmail = "myemail@yahoo.com"; // can be any email id System.out.println("SSLEmail Start"); Properties props = new Properties(); props.put("mail.smtp.host", "smtp.gmail.com"); //SMTP Host props.put("mail.smtp.socketFactory.port", "465"); //SSL Port props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); //SSL Factory Class props.put("mail.smtp.auth", "true"); //Enabling SMTP Authentication props.put("mail.smtp.port", "465"); //SMTP Port Authenticator auth = new Authenticator() { //override the getPasswordAuthentication method protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(fromEmail, password); } }; Session session = Session.getDefaultInstance(props, auth); System.out.println("Session created"); EmailUtil.sendEmail(session, toEmail,"SSLEmail Testing Subject", "SSLEmail Testing Body"); EmailUtil.sendAttachmentEmail(session, toEmail,"SSLEmail Testing Subject with Attachment", "SSLEmail Testing Body with Attachment"); EmailUtil.sendImageEmail(session, toEmail,"SSLEmail Testing Subject with Image", "SSLEmail Testing Body with Image"); }}
Chương trình này gần giống với kiểu xác thực TLS ở trên, chỉ có một vài thuộc tính là khác nhau. Như bạn có thể thấy, ta đang gọi một số phương thức khác từ class EmailUtil để gửi file đính kèm và hình ảnh trong email nhưng ta chưa định nghĩa chúng. Thực ra, chúng tôi đã cố tình giữ chúng lại để trình bày sau và giữ cho phần đầu của hướng dẫn đơn giản hơn.
Để gửi một file dưới dạng đính kèm, chúng ta cần tạo một đối tượng javax.mail.internet.MimeBodyPart và javax.mail.internet.MimeMultipart. Đầu tiên, thêm phần body cho phần tin nhắn text trong email, và sau đó sử dụng FileDataSource để đính kèm file vào phần thứ hai của multipart body. Phương thức đó sẽ trông như thế này:
/**
* Utility method to send email with attachment
* @param session
* @param toEmail
* @param subject
* @param body
*/
public static void sendAttachmentEmail(Session session, String toEmail, String subject, String body){
try{
MimeMessage msg = new MimeMessage(session);
msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
msg.addHeader("format", "flowed");
msg.addHeader("Content-Transfer-Encoding", "8bit");
msg.setFrom(new InternetAddress("no_reply@example.com", "NoReply-JD"));
msg.setReplyTo(InternetAddress.parse("no_reply@example.com", false));
msg.setSubject(subject, "UTF-8");
msg.setSentDate(new Date());
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
// Create the message body part
BodyPart messageBodyPart = new MimeBodyPart();
// Fill the message
messageBodyPart.setText(body);
// Create a multipart message for attachment
Multipart multipart = new MimeMultipart();
// Set text message part
multipart.addBodyPart(messageBodyPart);
// Second part is attachment
messageBodyPart = new MimeBodyPart();
String filename = "abc.txt";
DataSource source = new FileDataSource(filename);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(filename);
multipart.addBodyPart(messageBodyPart);
// Send the complete message parts
msg.setContent(multipart);
// Send message
Transport.send(msg);
System.out.println("EMail Sent Successfully with attachment!!");
}catch (MessagingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
Chương trình có thể trông phức tạp nhưng thực ra nó khá đơn giản. Chỉ cần tạo một body part cho phần tin nhắn text và một body part khác cho file đính kèm, sau đó thêm tất cả vào multipart. Bạn cũng có thể mở rộng phương thức này để đính kèm nhiều file cùng một lúc
/**
* Utility method to send image in email body
* @param session
* @param toEmail
* @param subject
* @param body
*/
public static void sendImageEmail(Session session, String toEmail, String subject, String body){
try{
MimeMessage msg = new MimeMessage(session);
msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
msg.addHeader("format", "flowed");
msg.addHeader("Content-Transfer-Encoding", "8bit");
msg.setFrom(new InternetAddress("no_reply@example.com", "NoReply-JD"));
msg.setReplyTo(InternetAddress.parse("no_reply@example.com", false));
msg.setSubject(subject, "UTF-8");
msg.setSentDate(new Date());
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
// Create the message body part
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText(body);
// Create a multipart message for attachment
Multipart multipart = new MimeMultipart();
// Set text message part
multipart.addBodyPart(messageBodyPart);
// Second part is image attachment
messageBodyPart = new MimeBodyPart();
String filename = "image.png";
DataSource source = new FileDataSource(filename);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(filename);
//Trick is to add the content-id header here
messageBodyPart.setHeader("Content-ID", "image_id");
multipart.addBodyPart(messageBodyPart);
//third part for displaying image in the email body
messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent("<h1>Attached Image</h1>" +
"<img src='cid:image_id'>", "text/html");
multipart.addBodyPart(messageBodyPart);
//Set the multipart message to the email message
msg.setContent(multipart);
// Send message
Transport.send(msg);
System.out.println("EMail Sent Successfully with image!!");
}catch (MessagingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
Vì chúng ta có thể tạo body của tin nhắn email dạng HTML, nếu file hình ảnh được đặt tại một vị trí nào đó trên server, chúng ta có thể sử dụng thẻ img để hiển thị chúng trong nội dung email. Nhưng đôi khi chúng ta muốn đính kèm hình ảnh vào email và sau đó hiển thị nó ngay trong trong nội dung email. Chắc hẳn bạn đã thấy nhiều email có hình ảnh đính kèm và trong chính phần nội dung cũng hiển thị các hình ảnh đó.
Mẹo ở đây là ta sẽ đính kèm file hình ảnh giống như bất kỳ file đính kèm nào khác, sau đó đặt header Content-ID cho file hình ảnh và sử dụng cùng content ID đó trong phần nội dung email với <img src='cid:image_id'>.
/**
* Utility method to send image in email body
* @param session
* @param toEmail
* @param subject
* @param body
*/
public static void sendImageEmail(Session session, String toEmail, String subject, String body){
try{
MimeMessage msg = new MimeMessage(session);
msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
msg.addHeader("format", "flowed");
msg.addHeader("Content-Transfer-Encoding", "8bit");
msg.setFrom(new InternetAddress("no_reply@example.com", "NoReply-JD"));
msg.setReplyTo(InternetAddress.parse("no_reply@example.com", false));
msg.setSubject(subject, "UTF-8");
msg.setSentDate(new Date());
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
// Create the message body part
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText(body);
// Create a multipart message for attachment
Multipart multipart = new MimeMultipart();
// Set text message part
multipart.addBodyPart(messageBodyPart);
// Second part is image attachment
messageBodyPart = new MimeBodyPart();
String filename = "image.png";
DataSource source = new FileDataSource(filename);
messageBodyPart.setDataHandler(new DataHandler(source));
messageBodyPart.setFileName(filename);
//Trick is to add the content-id header here
messageBodyPart.setHeader("Content-ID", "image_id");
multipart.addBodyPart(messageBodyPart);
//third part for displaying image in the email body
messageBodyPart = new MimeBodyPart();
messageBodyPart.setContent("<h1>Attached Image</h1>" +
"<img src='cid:image_id'>", "text/html");
multipart.addBodyPart(messageBodyPart);
//Set the multipart message to the email message
msg.setContent(multipart);
// Send message
Transport.send(msg);
System.out.println("EMail Sent Successfully with image!!");
}catch (MessagingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
javax.mail.MessagingException xảy ra khi hệ thống của bạn không thể phân giải địa chỉ IP cho SMTP server. Có thể là do hostname sai hoặc máy chủ không thể truy cập được từ nó. Ví dụ, địa chỉ chính xác của máy chủ GMail SMTP là smtp.gmail.com và ta sẽ gặp lỗi nếu dùng smtp.google.com. Nếu hostname chắc chắn đúng, hãy thử dùng lệnh ping để kiểm tra liệu hệ thống của bạn có thể truy cập được nó.pankaj@Pankaj:~/CODE$ ping smtp.gmail.com PING gmail-smtp-msa.l.google.com (74.125.129.108): 56 data bytes 64 bytes from 74.125.129.108: icmp_seq=0 ttl=46 time=38.308 ms 64 bytes from 74.125.129.108: icmp_seq=1 ttl=46 time=42.247 ms 64 bytes from 74.125.129.108: icmp_seq=2 ttl=46 time=38.164 ms 64 bytes from 74.125.129.108: icmp_seq=3 ttl=46 time=53.153 ms
Transport.send(), hãy kiểm tra xem SMTP port có chính xác không. Nếu port đúng, hãy sử dụng telnet để xác minh rằng nó có thể truy cập được từ máy của bạn (giốn như output như dưới đây):pankaj@Pankaj:~/CODE$ telnet smtp.gmail.com 587 Trying 2607:f8b0:400e:c02::6d... Connected to gmail-smtp-msa.l.google.com. Escape character is '^]'. 220 mx.google.com ESMTP sx8sm78485186pab.5 - gsmtp HELO 250 mx.google.com at your service
Ở trên là những ví dụ sử dụng JavaMail để gửi mail trong Java bằng SMTP server với các giao thức xác thực khác nhau, cũng như với file đính kèm và hình ảnh. Chúng tôi hy vọng nó sẽ giúp bạn giải quyết các yêu cầu gửi email trong các chương trình Java của bạn.