CyStack logo
  • Sản phẩm & Dịch vụ
  • Giải pháp
  • Bảng giá
  • Công ty
  • Tài liệu
Vi

vi

Trang chủHướng dẫnHướng dẫn gửi email bằng SMTP trong Java với JavaMail từ A đến Z
Java

Hướng dẫn gửi email bằng SMTP trong Java với JavaMail từ A đến Z

CyStack blog 8 phút để đọc
CyStack blog07/07/2025
Locker Avatar

Bao Tran

Web Developer

Locker logo social
Reading Time: 8 minutes

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.

Gửi email bằng JavaMail

Ví dụ dùng JavaMail

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:

  1. Tạo đối tượng javax.mail.Session .
  2. Tạo đối tượng 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.
  3. Sử dụng 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.

Ví dụ chương trình dùng JavaMail

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.

Gửi email không cần xác thực trong Java bằng SMTP

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.

Gửi email với xác thực TLS trong Java SMTP

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ử.

Ví dụ Java SMTP với xác thực SSL

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.

Ví dụ gửi email trong Java với file đính kèm bằng JavaMail

Để 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.MimeBodyPartjavax.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

Ví dụ gửi email kèm hình ảnh bằng JavaMail

/**
 * 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();
	}
}

Các mẹo khắc phục lỗi JavaMail API

  1. Lỗi 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
  1. Nếu chương trình của bạn bị kẹt khi gọi phương thức 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

Tổng kết

Ở 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.

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp 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.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất