JavaMail示例 – 使用SMTP在Java中发送邮件

今天我们将研究Java程序中发送电子邮件的JavaMail示例。发送电子邮件是现实生活应用中的常见任务之一,这就是为什么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中的一些标头属性,它们由电子邮件客户端用于正确呈现和显示电子邮件消息。程序的其余部分很简单且容易理解。现在让我们创建一个不需要身份验证的发送电子邮件的程序。

使用SMTP在Java中发送邮件,无需身份验证

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对象。我们需要将mail.smtp.host属性设置为SMTP服务器主机。如果SMTP服务器未在默认端口(25)上运行,则还需要设置mail.smtp.port属性。只需将此程序与您的无身份验证SMTP服务器一起运行,并将收件人电子邮件ID设置为您自己的电子邮件ID,您将立即收到电子邮件。该程序易于理解且运行良好,但在现实生活中,大多数SMTP服务器都使用某种身份验证,例如TLS或SSL身份验证。因此,我们现在将看到如何为这些身份验证协议创建Session对象。

在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);
         // 诀窍是在此处添加内容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示例,用于使用SMTP服务器在Java中发送邮件,支持不同的身份验证协议、附件和图片。我希望它能解决您在Java程序中发送电子邮件的所有需求。

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