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

时间:2020-02-23 14:37:01  来源:igfitidea点击:

今天,我们将研究JavaMail Example在Java程序中发送电子邮件。
发送电子邮件是现实生活中应用程序中的常见任务之一,这就是Java提供可靠的JavaMail API的原因,我们可以使用它来使用SMTP服务器发送电子邮件。
JavaMail API支持TLS和SSL身份验证来发送电子邮件。

JavaMail示例

今天,我们将学习如何使用JavaMail API通过不带身份验证,TLS和SSL身份验证的SMTP服务器发送电子邮件,以及如何发送附件以及在电子邮件正文中附加和使用图像。
对于TLS和SSL身份验证,我使用的是GMail SMTP服务器,因为它同时支持两者。

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程序包含以下步骤:

  • 创建javax.mail.Session对象

  • 创建javax.mail.internet.MimeMessage对象时,我们必须在此对象中设置不同的属性,例如收件人电子邮件地址,电子邮件主题,回复电子邮件,电子邮件正文,附件等。

  • 使用javax.mail.Transport发送电子邮件。

创建会话的逻辑因SMTP服务器的类型而异,例如,如果SMTP服务器不需要任何身份验证,我们可以创建具有一些简单属性的Session对象,而如果它需要TLS或者SSL身份验证,则创建逻辑将有所不同。

因此,我将创建一个包含一些实用程序方法的实用程序类来发送电子邮件,然后将该实用程序方法用于不同的SMTP服务器。

JavaMail示例程序

我们的EmailUtil类只有一个发送电子邮件的方法,如下所示,它需要javax.mail.Session和一些其他必填字段作为参数。
为简单起见,一些参数是硬编码的,但是您可以扩展此方法以传递它们或者从某些配置文件中读取它。

package com.theitroad.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("[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无需验证即可使用SMTP发送Java邮件

package com.theitroad.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属性。
只需使用您的无身份验证SMTP服务器并通过将收件人电子邮件ID设置为您自己的电子邮件ID来运行该程序,您将很快收到该电子邮件。

该程序易于理解并且运行良好,但是在现实生活中,大多数SMTP服务器都使用某种身份验证,例如TLS或者SSL身份验证。
现在,我们将看到如何为这些身份验证协议创建Session对象。

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

package com.theitroad.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
		
              //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");
		
	}

	
}

由于我使用的是所有人都可以访问的GMail SMTP服务器,因此您可以在上述程序中设置正确的变量并自己运行。

具有SSL身份验证的Java SMTP示例

package com.theitroad.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() {
			//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");

	}

}

该程序与TLS身份验证几乎相同,只是某些属性不同。
如您所见,我正在从EmailUtil类调用一些其他方法来在电子邮件中发送附件和图像,但我尚未定义它们。
实际上,我让它们稍后显示,并在本教程开始时保持简单。

JavaMail示例–使用Java发送带有附件的邮件

要发送文件作为附件,我们需要创建一个对象javax.mail.internet.MimeBodyPart和javax.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));
	      
       //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();
	}
}

该程序乍一看可能看起来很复杂,但很简单,只需为短信创建一个正文部分,为附件创建另一个正文部分,然后将其添加到多部分中。
您也可以扩展此方法以附加多个文件。

JavaMail示例–使用Java发送带有图片的邮件

由于我们可以创建HTML正文消息,因此,如果图像文件位于某个服务器位置,则可以使用img元素在消息中显示它们。
但是有时我们想将图像附加到电子邮件中,然后在电子邮件正文中使用它。
您一定已经看过这么多带有图像附件的电子邮件,并且这些电子邮件也在电子邮件中使用。

诀窍是像其他任何附件一样附加图像文件,然后设置图像文件的Content-ID标头,然后在电子邮件正文中使用与<img src ='cid:image_id'>相同的内容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));
	      
       //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();
	}
}

JavaMail API故障排除技巧

  • 当您的系统无法解析SMTP服务器的IP地址时,可能会出现java.net.UnknownHostException异常,这可能是错误的或者无法从网络访问。
    例如,GMail SMTP服务器是smtp.gmail.com,如果我使用smtp.google.com,则会收到此异常。
    如果主机名正确,请尝试通过命令行ping服务器,以确保可以从系统访问该服务器。

  • 如果您的程序停留在Transport send()方法调用中,请检查SMTP端口是否正确。
    如果正确,请使用telnet验证它是否可以从您的计算机访问,您将获得如下所示的输出。