[Java] Mail 발송


Development note/Java  2020. 2. 3. 23:08

안녕하세요. 명월입니다.


이 글은 Java에서 메일(javax.mail)을 보내는 방법에 대한 글입니다.


프로그램상에서 우리가 메일 발송에 관해서는 여러가지 형태로 사용할 수 있습니다. 회원 가입시에 가입 인증이나 패스워드 찾기 등등이 있고, 또 여러가지 알람 기능으로도 메일을 많이 보냅니다.

최근에는 sns가 많이 생겨서 sns으로 메시지를 보내는 방법으로도 많이 사용됩니다만 그래도 아직도 메일 발송 기능은 없어지는 경우는 없는 것 같네요.


저는 google mail(gmail)를 통해서 메일을 보내는 예제입니다. 이전에 python으로 메일 보내는 방법에 대해 소개할 때 설정한 적이 있습니다.

링크 - [Python] 메일(smtplib)을 보내는 방법


Gmail이외에 Naver나 Daum을 통해서도 설정이 가능합니다.

구글 메일 참조 - https://support.google.com/a/answer/176600?hl=ko

네이버 메일 참조 - https://mail.naver.com/option/imap

다음 메일 참조 - https://cs.daum.net/faq/43/9234.html#35953


먼저 크롬에 접속해서 오른쪽 상단에 회원 정보로 갑니다.(로그인이 되지 않았으면 로그인을 먼저 합니다.)

글 계정으로 가서 보안 탭의 보안 수준이 낮은 앱의 액세스 탭으로 갑니다.

보안 수준이 낮은 앱의 사용을 체크합니다. 이 체크를 안하면 외부에서 구글 메일을 사용하지 못하게 하는 것이기 때문에 사용하기로 바꿔도 아이디 패스워드 노출이 안 된다면 보안상의 큰 문제는 없습니다.

java에서 메일을 발송하는 소스를 작성하기 전에 pom.xml에 메일 라이브러리를 등록해야 합니다.

레포지토리 - https://mvnrepository.com/artifact/javax.mail/mail

<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
<dependency>
  <groupId>javax.mail</groupId>
  <artifactId>mail</artifactId>
  <version>1.4.7</version>
</dependency>

메일 발송은 꼭 웹 환경에서 만들 필요는 없기 때문에 저는 console 환경에서 작성했습니다.

import java.io.File;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
// 시작함수는 아래쪽에 있습니다.
public class Program implements Runnable {

  // main에서 run 함수가 호출되면 메일 발송을 시작합니다.
  @Override
  public void run() {
    try {
      // 메일 환경 변수 설정입니다.
      Properties props = new Properties();
      // 메일 프로토콜은 gmail를 이용할 것이기 때문에 smtp로 사용합니다.
      props.setProperty("mail.transport.protocol", "smtp");
      // 메일 호스트 주소를 설정합니다.
      props.setProperty("mail.host", "smtp.gmail.com");
      // ID, Password 설정이 필요합니다.
      props.put("mail.smtp.auth", "true");
      // port는 465입니다.
      props.put("mail.smtp.port", "465");
      // ssl를 사용할 경우 설정합니다.
      props.put("mail.smtp.socketFactory.port", "465");
      props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
      props.put("mail.smtp.socketFactory.fallback", "false");
      props.setProperty("mail.smtp.quitwait", "false");
      // id와 password를 설정하고 session을 생성합니다.
      Session session = Session.getInstance(props, new Authenticator() {
        protected PasswordAuthentication getPasswordAuthentication() {
          return new PasswordAuthentication("id", "password");
        }
      });
      // 디버그 모드입니다.
      session.setDebug(true);
      // 메일 메시지를 만들기 위한 클래스를 생성합니다.
      MimeMessage message = new MimeMessage(session);
      // 송신자 설정
      message.setFrom(getAddress("nowonbun@gmail.com"));
      // 수신자 설정
      message.addRecipients(Message.RecipientType.TO, getAddresses("nowonbun@gmail.com,nowonbun@gmail.com"));
      // 참조 수신자 설정
      message.addRecipients(Message.RecipientType.CC, getAddresses("nowonbun@gmail.com"));
      // 숨은 참조 수신자 설정
      message.addRecipients(Message.RecipientType.BCC, getAddresses("nowonbun@gmail.com"));
      
      // 메일 제목을 설정합니다.
      message.setSubject("Test Mail");
      // 메일 내용을 설정을 위한 클래스를 설정합니다.
      message.setContent(new MimeMultipart());
      
      // 메일 내용을 위한 Multipart클래스를 받아온다. (위 new MimeMultipart()로 넣은 클래스입니다.)
      Multipart mp = (Multipart) message.getContent();
      // html 형식으로 본문을 작성해서 바운더리에 넣습니다.
      mp.addBodyPart(getContents("<html><head></head><body>Hello Test<br><img src=\"cid:image\" ></body></html>"));
      // 첨부 파일을 추가합니다.
      mp.addBodyPart(getFileAttachment("test.xlsx"));
      // 이미지 파일을 추가해서 contextId를 설정합니다. contextId는 위 본문 내용의 cid로 링크가 설정 가능합니다.
      mp.addBodyPart(getImage("capture.png", "image"));
      // 메일을 보냅니다.
      Transport.send(message);
    } catch (Throwable e) {
      e.printStackTrace();
    }
  }
  // 이미지를 로컬로 부터 읽어와서 BodyPart 클래스로 만든다. (바운더리 변환)
  private BodyPart getImage(String filename, String contextId) throws MessagingException {
    // 파일을 읽어와서 BodyPart 클래스로 받는다.
    BodyPart mbp = getFileAttachment(filename);
    if (contextId != null) {
      // ContextId 설정
      mbp.setHeader("Content-ID", "<" + contextId + ">");
    }
    return mbp;
  }
  // 파일을 로컬로 부터 읽어와서 BodyPart 클래스로 만든다. (바운더리 변환)
  private BodyPart getFileAttachment(String filename) throws MessagingException {
    // BodyPart 생성
    BodyPart mbp = new MimeBodyPart();
    // 파일 읽어서 BodyPart에 설정(바운더리 변환)
    File file = new File(filename);
    DataSource source = new FileDataSource(file);
    mbp.setDataHandler(new DataHandler(source));
    mbp.setDisposition(Part.ATTACHMENT);
    mbp.setFileName(file.getName());
    return mbp;
  }
  // 메일의 본문 내용 설정
  private BodyPart getContents(String html) throws MessagingException {
    BodyPart mbp = new MimeBodyPart();
    // setText를 이용할 경우 일반 텍스트 내용으로 설정된다.
    // mbp.setText(html);
    // html 형식으로 설정
    mbp.setContent(html, "text/html; charset=utf-8");
    return mbp;
  }
  // String으로 된 메일 주소를 Address 클래스로 변환
  private Address getAddress(String address) throws AddressException {
    return new InternetAddress(address);
  }
  // String으로 된 복수의 메일 주소를 콤마(,)의 구분으로 Address array형태로 변환
  private Address[] getAddresses(String addresses) throws AddressException {
    String[] array = addresses.split(",");
    Address[] ret = new Address[array.length];
    for (int i = 0; i < ret.length; i++) {
      ret[i] = getAddress(array[i]);
    }
    return ret;
  }
  // 시작 함수 Program을 생성해서 run을 실행합니다.
  public static void main(String[] args) {
    Program p = new Program();
    p.run();
  }
}

제가 session의 디버그 모드를 했기 때문에 메일 서버와 주고 받는 메시지의 상태가 나옵니다. 혹시 프로토콜에 추가할 내용이 있으면 이 로그를 보고 추가하면 됩니다.


메일이 발송이 되었기 때문에 이제 제 메일함에 메일이 제대로 도착했는지 확인합니다.

메일이 잘 전송이 되었습니다.


여기까지 Java에서 메일(javax.mail)을 보내는 방법에 대한 설명이었습니다.


궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.