SMTP를 사용하여 Java에서 메일 보내는 JavaMail 예제

오늘은 Java 프로그램에서 이메일을 보내는 JavaMail 예제를 살펴보겠습니다. 이메일 보내기는 실생활 애플리케이션에서의 일반적인 작업 중 하나이며, 그래서 Java는 SMTP 서버를 사용하여 이메일을 보낼 수 있는 견고한 JavaMail API를 제공합니다. JavaMail API는 이메일 보내기에 대해 TLS 및 SSL 인증을 모두 지원합니다.

JavaMail 예제

오늘은 SMTP 서버를 사용하여 JavaMail API를 사용하여 이메일을 보내는 방법을 배우고, 인증 없이, TLS 및 SSL 인증을 사용하는 방법, 그리고 첨부 파일을 보내고 이메일 본문에 이미지를 첨부하고 사용하는 방법을 알아보겠습니다. TLS 및 SSL 인증의 경우, 양쪽 모두를 지원하기 때문에 Gmail SMTP 서버를 사용하고 있습니다. 프로젝트 요구 사항에 따라 Java 메일 서버를 선택할 수도 있습니다. JavaMail API는 표준 JDK의 일부가 아니므로 공식 웹 사이트인 JavaMail 홈 페이지에서 다운로드해야 합니다. 최신 버전의 JavaMail 참조 구현을 다운로드하고 프로젝트 빌드 경로에 포함시킵니다. jar 파일 이름은 javax.mail.jar입니다. Maven 기반 프로젝트를 사용하는 경우, 프로젝트에 아래 종속성을 추가하면 됩니다.이메일을 보내는 Java 프로그램에는 다음 단계가 포함됩니다:

<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 예제 프로그램

다음과 같은 이메일 유틸 클래스를 가지고 있습니다. 이 클래스는 이메일을 보내는 단일 메서드를 가지고 있으며, 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 속성도 설정해야 합니다. 이 프로그램을 인증되지 않은 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 인증과 거의 동일하지만, 몇 가지 속성이 다릅니다. 저번 예제에서 이미일을 보내는 메서드를 호출한 것을 볼 수 있지만, 아직 정의하지 않았습니다. 사실 저는 나중에 보여주기 위해 그것들을 따로 두었고, 튜토리얼의 시작 부분에서는 간단하게 유지하기 위해 두었습니다.

JavaMail 예제 – 첨부 파일과 함께 자바로 메일 보내기

파일을 첨부 파일로 보내려면 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 예제 – 자바로 이미지와 함께 메일 보내기

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 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
    
  2. 프로그램이 Transport send() 메서드 호출에서 멈춘 경우 SMTP 포트가 올바른지 확인하십시오. 올바른 경우 텔넷을 사용하여 시스템에서 접근할 수 있는지 확인하고 다음과 같은 출력을 얻으십시오.

    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