JavaMail範例 – 使用SMTP在Java中發送郵件

今天我們將研究 JavaMail 範例,以在 Java 程式中發送郵件。發送郵件是現實生活應用中的常見任務之一,這就是為什麼 Java 提供了強大的 JavaMail API,我們可以使用它來使用 SMTP 伺服器發送郵件。JavaMail API 支援使用 TLS 和 SSL 認證發送郵件。

JavaMail 範例

今天我們將學習如何使用 JavaMail API 使用 SMTP 伺服器發送郵件,不需要身份驗證,以及如何使用 TLS 和 SSL 認證發送郵件,以及如何發送附件並在郵件正文中附加和使用圖像。對於 TLS 和 SSL 認證,我使用 Gmail SMTP 伺服器,因為它支援這兩種認證。您也可以根據項目需求選擇使用 Java 郵件伺服器。JavaMail API 不是標準 JDK 的一部分,因此您需要從其官方網站即 JavaMail 主頁下載它。下載最新版本的 JavaMail 參考實現並將其包含在您的項目構建路徑中。jar 檔案名稱將是 javax.mail.jar。如果您使用基於 Maven 的項目,只需在您的項目中添加以下依賴。

<dependency>
	<groupId>com.sun.mail</groupId>
	<artifactId>javax.mail</artifactId>
	<version>1.5.5</version>
</dependency>

發送電子郵件的 Java 程式包含以下步驟:

  1. 創建javax.mail.Session對象
  2. 創建javax.mail.internet.MimeMessage對象,我們必須在該對象中設置不同的屬性,例如收件人電子郵件地址、郵件主題、回復郵件地址、郵件正文、附件等
  3. 使用javax.mail.Transport來發送電子郵件消息

根據SMTP服務器的類型,創建會話的邏輯有所不同,例如,如果SMTP服務器不需要任何身份驗證,我們可以使用一些簡單的屬性來創建會話對象,而如果它需要TLS或SSL驗證,則創建的邏輯將有所不同。因此,我將創建一個實用程序類,其中包含一些用於發送電子郵件的實用方法,然後我將使用這些實用程序方法與不同的SMTP服務器

JavaMail示例程序

我們的EmailUtil類只有一個方法來發送郵件,如下所示,它需要javax.mail.Session和一些其他必需的字段作為參數。為了保持簡單,一些參數是硬編碼的,但您可以擴展此方法以傳遞它們或從某些配置文件中讀取它們

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);
	      //設置消息標頭
	      msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
	      msg.addHeader("format", "flowed");
	      msg.addHeader("Content-Transfer-Encoding", "8bit");

	      msg.setFrom(new InternetAddress("[email protected]", "NoReply-JD"));

	      msg.setReplyTo(InternetAddress.parse("[email protected]", 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();
	    }
	}
}

請注意,我正在設置MimeMessage中的一些標頭屬性,這些屬性由電子郵件客戶端用於正確渲染和顯示電子郵件消息。程序的其餘部分都很簡單,易於理解。現在讓我們創建我們的程序以在沒有身份驗證的情況下發送郵件。

在Java中使用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 protected]";
	    
	    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");
	}

}

请注意,我正在使用Session.getInstance()通过传递Properties对象来获取Session对象。我们需要使用SMTP服务器主机设置mail.smtp.host属性。如果SMTP服务器不在默认端口(25)上运行,则还需要设置mail.smtp.port属性。只需将收件人电子邮件ID设置为您自己的电子邮件ID,并运行此程序,您将立即收到电子邮件。该程序简单易懂,并且运行良好,但是在实际生活中,大多数SMTP服务器使用某种形式的身份验证,如TLS或SSL身份验证。因此,现在我们将看到如何为这些身份验证协议创建会话对象。

在Java SMTP中使用TLS身份验证发送电子邮件

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 = "[email protected]"; //requires valid gmail id
		final String password = "mypassword"; // correct password for gmail id
		final String toEmail = "[email protected]"; // 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
		
                //创建Authenticator对象以传递给Session.getInstance参数
		Authenticator auth = new Authenticator() {
			//覆盖getPasswordAuthentication方法
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(fromEmail, password);
			}
		};
		Session session = Session.getInstance(props, auth);
		
		EmailUtil.sendEmail(session, toEmail,"TLSEmail Testing Subject", "TLSEmail Testing Body");
		
	}

	
}

由于我正在使用全局可访问的GMail SMTP服务器,您可以在上述程序中设置正确的变量并自行运行。相信我,它有效! 🙂

Java SMTP 示例,带 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 = "[email protected]"; //requires valid gmail id
		final String password = "mypassword"; // correct password for gmail id
		final String toEmail = "[email protected]"; // 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() {
			// 重写 getPasswordAuthentication 方法
			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");

	}

}

该程序与 TLS 身份验证几乎相同,只是一些属性不同。如您所见,我从 EmailUtil 类调用了一些其他方法来发送邮件中的附件和图片,但我还没有定义它们。实际上,我将它们保留到后面展示,并在教程开始时保持简单。

JavaMail 示例 – 在 Java 中发送带附件的邮件

要将文件作为附件发送,我们需要创建 javax.mail.internet.MimeBodyPartjavax.mail.internet.MimeMultipart 的对象。首先在电子邮件中添加文本消息的正文部分,然后使用 FileDataSource 将文件附加到多部分正文的第二部分。该方法如下所示。

/**
 * 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("[email protected]", "NoReply-JD"));

	     msg.setReplyTo(InternetAddress.parse("[email protected]", false));

	     msg.setSubject(subject, "UTF-8");

	     msg.setSentDate(new Date());

	     msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
	      
         // 创建消息正文部分
         BodyPart messageBodyPart = new MimeBodyPart();

         // 填充消息
         messageBodyPart.setText(body);
         
         // 为附件创建多部分消息
         Multipart multipart = new MimeMultipart();

         // 设置文本消息部分
         multipart.addBodyPart(messageBodyPart);

         // 第二部分是附件
         messageBodyPart = new MimeBodyPart();
         String filename = "abc.txt";
         DataSource source = new FileDataSource(filename);
         messageBodyPart.setDataHandler(new DataHandler(source));
         messageBodyPart.setFileName(filename);
         multipart.addBodyPart(messageBodyPart);

         // 发送完整的消息部分
         msg.setContent(multipart);

         // 发送消息
         Transport.send(msg);
         System.out.println("EMail Sent Successfully with attachment!!");
      }catch (MessagingException e) {
         e.printStackTrace();
      } catch (UnsupportedEncodingException e) {
		 e.printStackTrace();
	}
}

該程序乍一看可能很複雜,但其實很簡單,只需創建一個用於文本消息的正文部分,另一個用於附件,然後將它們添加到多部分。您可以擴展此方法以附加多個文件。

JavaMail示例 – 使用圖片在Java中發送郵件

由於我們可以創建HTML正文消息,如果圖像文件位於某個服務器位置,我們可以使用img元素在消息中顯示它們。但有時我們想要將圖像附加到電子郵件中,然後在電子郵件正文中使用它們。您可能已經看過很多帶有圖像附件並且也在電子郵件消息中使用的電子郵件。訣竅是像任何其他附件一樣附加圖像文件,然後設置Content-ID標頭以及在電子郵件消息正文中使用相同的內容ID以<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("[email protected]", "NoReply-JD"));

	     msg.setReplyTo(InternetAddress.parse("[email protected]", false));

	     msg.setSubject(subject, "UTF-8");

	     msg.setSentDate(new Date());

	     msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
	      
         // 創建消息正文部分
         BodyPart messageBodyPart = new MimeBodyPart();

         messageBodyPart.setText(body);
         
         // 為附件創建多部分消息
         Multipart multipart = new MimeMultipart();

         // 設置文本消息部分
         multipart.addBodyPart(messageBodyPart);

         // 第二部分是圖像附件
         messageBodyPart = new MimeBodyPart();
         String filename = "image.png";
         DataSource source = new FileDataSource(filename);
         messageBodyPart.setDataHandler(new DataHandler(source));
         messageBodyPart.setFileName(filename);
         // 設置content-id標頭的訣竅在此處
         messageBodyPart.setHeader("Content-ID", "image_id");
         multipart.addBodyPart(messageBodyPart);

         // 在電子郵件正文中顯示圖像的第三部分
         messageBodyPart = new MimeBodyPart();
         messageBodyPart.setContent("

Attached Image

" + "", "text/html"); multipart.addBodyPart(messageBodyPart); // 將多部分消息設置為電子郵件消息 msg.setContent(multipart); // 發送消息 Transport.send(msg); System.out.println("EMail Sent Successfully with image!!"); }catch (MessagingException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } }

JavaMail API疑難排解技巧

  1. java.net.UnknownHostException 出現時,表示您的系統無法解析 SMTP 伺服器的 IP 地址,可能是錯誤的或無法從您的網路訪問。例如,GMail SMTP 伺服器是 smtp.gmail.com,如果我使用 smtp.google.com,就會出現此異常。如果主機名稱正確,請嘗試通過命令行 ping 伺服器,以確保它從您的系統可訪問。

    pankaj@Pankaj:~/CODE$ ping smtp.gmail.com
    PING gmail-smtp-msa.l.google.com (74.125.129.108): 56 data bytes
    64 位元組來自 74.125.129.108: icmp_seq=0 ttl=46 時間=38.308 毫秒
    64 位元組來自 74.125.129.108: icmp_seq=1 ttl=46 時間=42.247 毫秒
    64 位元組來自 74.125.129.108: icmp_seq=2 ttl=46 時間=38.164 毫秒
    64 位元組來自 74.125.129.108: icmp_seq=3 ttl=46 時間=53.153 毫秒
    
  2. 如果您的程序在 Transport send() 方法调用中卡住,请检查 SMTP 端口是否正确。如果正确,请使用 telnet 验证它是否从您的机器可访问,您将得到以下输出。

    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
    

这就是 JavaMail 示例的全部内容,它用于在 Java 中使用 SMTP 服务器发送邮件,支持不同的身份验证协议、附件和图片。我希望它能满足您在 Java 程序中发送电子邮件的所有需求。

Source:
https://www.digitalocean.com/community/tutorials/javamail-example-send-mail-in-java-smtp