2022-09-02
단순 메일 발송이 아닌 첨부파일 그중에서 엑셀 파일과 함께 발송하는 방법을 알아보자. 우선적으로 구현 class는 총 3개이며, 메일 계정 인증 유틸 / 메일 발송 유틸 / 실제 메일을 발송하는 컨트롤러 이렇게 구성했다.
0. 라이브러리
자신의 build.gradle 아래 2가지의 라이브러리를 추가해야 한다.
// 엑셀관련 workbook 라이브러리
// https://mvnrepository.com/artifact/org.apache.poi/poi
implementation group: 'org.apache.poi', name: 'poi', version: '5.2.2'
// https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml
implementation group: 'org.apache.poi', name: 'poi-ooxml', version: '5.2.2'
1. 메일 계정 인증
계정 인증 단에 클래스이다. 사용자 아이디와 비밀번호를 파라미터로 받아 인증정보를 생성한다.
import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
public class MailAuthUtil extends Authenticator{
//비밀번호 인증
PasswordAuthentication pa;
//파라미터 있는 경우 생성자
public MailAuthUtil(String id, String pw) {
String sendId =id ;
String sendPw =pw;
System.out.println("sendId -> " + sendId);
System.out.println("sendPw -> " + sendPw);
pa = new PasswordAuthentication(sendId, sendPw);
}
//발송단계에서 인증 정보를 확인할 수 있음
public PasswordAuthentication getPasswordAuthentication() {
return pa;
}
}
2. 메일발송/엑셀파일 생성 유틸
메일 발송과 발송할 엑셀파일을 만드는 메서드가 포함되어 있는 유틸 클래스이다. 관련 내용은 주석으로 적어두었다.
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
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;
import javax.mail.internet.MimeUtility;
import javax.mail.util.ByteArrayDataSource;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class MailSendUtil {
//메일을 보내는 메소드(메일 계정 순서, 수신자)
public String mailSend(
MailAuthUtil MailAuthUtil
, String recevier
, String content
, String title
, Workbook wb) {
Properties prop = System.getProperties();
prop.put("mail.smtp.host", "smtp.gmail.com"); // 이메일 발송을 처리해줄 SMTP서버
prop.put("mail.smtp.starttls.enable", "true"); // TLS 통신여부 확인
prop.put("mail.smtp.auth", "true"); // SMTP 인증 여부
prop.put("mail.smtp.port", "587"); // TLS port 정보 입력 : 587
System.out.println("username info -> " + MailAuthUtil.getPasswordAuthentication().getUserName());
System.out.println("userPw info -> " + MailAuthUtil.getPasswordAuthentication().getPassword());
Authenticator auth = MailAuthUtil;
Session session = Session.getDefaultInstance(prop, auth); // 디폴트 세션을 계속 사용하도록 설정
// Session session = Session.getInstance(prop, auth); //항상 새로운 메일 객체 생성하도록 설정
MimeMessage mimeMessage = new MimeMessage(session);
try {
mimeMessage.setSentDate(new Date());// 보내는 날짜 지정
System.out.println("sender address -> " +MailAuthUtil.getPasswordAuthentication().getUserName());
mimeMessage.setFrom(new InternetAddress(MailAuthUtil.getPasswordAuthentication().getUserName(), "테스트계정", "UTF-8")); // 발송자를 지정한다. 발송자의 메일, 발송자명
// 수신자의 메일을 생성한다.
InternetAddress receiverAddress = new InternetAddress(recevier);
// Message.RecipientType.TO : 받는 수신자
// Message.RecipientType.CC : 참조 수신자
mimeMessage.setRecipient(Message.RecipientType.TO, receiverAddress); //수신정보 설정
mimeMessage.setSubject(title, "UTF-8"); // 메일의 제목 지정
Multipart mp = new MimeMultipart(); //멀티파트 객체 생성
System.out.println(" ===== file info body info setting . . . ===== ");
MimeBodyPart mbp1 = new MimeBodyPart();
mbp1.setContent(content, "text/html; charset=utf-8"); //메일 내용 셋팅
mp.addBodyPart(mbp1); // 파일송신시 보이는 텍스트 파일 멀티파트 담는다.
//만들어진 엑셀파일을 읽어들인다.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
wb.write(bos);
} catch (IOException e) {
e.printStackTrace();
}
//파일명 + 날짜
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
Date now = new Date();
String nowStr = dateFormat.format(now);
//excel 형식의 파일전달
DataSource fds = new ByteArrayDataSource(bos.toByteArray(), "application/vnd.ms-excel");
MimeBodyPart attachment = new MimeBodyPart();
attachment.setFileName(MimeUtility.encodeText("테스트파일_" + nowStr, "UTF-8","B")); // 파일이름설정
attachment.setDataHandler(new DataHandler(fds)); // 전달파일 핸들러
//멀티파트 형식으로 파일정보 추가
mp.addBodyPart(attachment);
//메일 전달내용에 해당 멀티파트(엑셀파일) 정보 추가
mimeMessage.setContent(mp);
System.out.println(" ===== file info setting end ===== ");
//메일 발송
Transport.send(mimeMessage);
} catch (AddressException ae) {
System.out.println("AddressException : " + ae);
return "fail";
} catch (MessagingException me) {
System.out.println("MessagingException : " + me);
return "fail";
} catch (UnsupportedEncodingException e) {
System.out.println("UnsupportedEncodingException : " + e);
return "fail";
}
return "success";
}
public Workbook makeEmailFormatListExcel(List<Map<String, String>> emailFormatList) {
Workbook wb = new XSSFWorkbook();
System.out.println("emailFormatList size -> "+ emailFormatList.size());
Sheet sheet = wb.createSheet("info");
int rownum = 0;
int cellnum = 0;
Row row = sheet.createRow(rownum++);
row.createCell(cellnum++).setCellValue("테스트이름");
row.createCell(cellnum++).setCellValue("테스트나이");
//데이터 루프 문 시작 가져온 데이터 만큼 반복
for(Map<String, String> emailFormatInfo: emailFormatList) {
System.out.println("emailFormatInfo -> " + emailFormatInfo.toString());
row = sheet.createRow(rownum++);
cellnum = 0;
row.createCell(cellnum++).setCellValue(emailFormatInfo.get("testName"));
row.createCell(cellnum++).setCellValue(emailFormatInfo.get("testAge"));
}
System.out.println("email info file make end");
return wb;
}
}
2-2. 2개 이상의 메일 계정 사용시
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
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;
import javax.mail.internet.MimeUtility;
import javax.mail.util.ByteArrayDataSource;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class MailSendUtil {
//메일을 보내는 메소드(메일 계정 순서, 수신자)
public String mailSend(
MailAuthUtil MailAuthUtil
, String recevier
, String content
, String title
, Workbook wb) {
Properties prop = System.getProperties();
// prop.put("mail.smtp.host", "smtp.gmail.com"); // 이메일 발송을 처리해줄 SMTP서버
prop.put("mail.smtp.starttls.enable", "true"); // TLS 통신여부 확인
prop.put("mail.transport.protocol", "smtp");
prop.put("mail.smtp.auth", "true"); // SMTP 인증 여부
prop.put("mail.smtp.port", "587"); // TLS port 정보 입력 : 587
System.out.println("username info -> " + MailAuthUtil.getPasswordAuthentication().getUserName());
System.out.println("userPw info -> " + MailAuthUtil.getPasswordAuthentication().getPassword());
// Authenticator auth = MailAuthUtil;
String SendId = newMerchantSettlementEmailSendUtils.getPasswordAuthentication().getUserName();
String SendPw = newMerchantSettlementEmailSendUtils.getPasswordAuthentication().getPassword();
Session session = Session.getDefaultInstance(prop);
MimeMessage mimeMessage = new MimeMessage(session);
//메일 발송 객체 생성
Transport transport = null;
try {
mimeMessage.setSentDate(new Date());// 보내는 날짜 지정
System.out.println("sender address -> " +MailAuthUtil.getPasswordAuthentication().getUserName());
mimeMessage.setFrom(new InternetAddress(MailAuthUtil.getPasswordAuthentication().getUserName(), "테스트계정", "UTF-8")); // 발송자를 지정한다. 발송자의 메일, 발송자명
// 수신자의 메일을 생성한다.
InternetAddress receiverAddress = new InternetAddress(recevier);
// Message.RecipientType.TO : 받는 수신자
// Message.RecipientType.CC : 참조 수신자
mimeMessage.setRecipient(Message.RecipientType.TO, receiverAddress); //수신정보 설정
mimeMessage.setSubject(title, "UTF-8"); // 메일의 제목 지정
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
wb.write(baos); //엑셀파일 바이트 스트립에 기록
} catch (IOException e) {
e.printStackTrace();
}
Multipart mp = new MimeMultipart(); //멀티파트 객체 생성
System.out.println(" ===== file info body info setting . . . ===== ");
MimeBodyPart mbp1 = new MimeBodyPart();
mbp1.setContent(content, "text/html; charset=utf-8"); //메일 내용 셋팅
mp.addBodyPart(mbp1); // 파일송신시 보이는 텍스트 파일 멀티파트 담는다.
//만들어진 엑셀파일을 읽어들인다.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
wb.write(bos);
} catch (IOException e) {
e.printStackTrace();
}
//파일명 + 날짜
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
Date now = new Date();
String nowStr = dateFormat.format(now);
//excel 형식의 파일전달
DataSource fds = new ByteArrayDataSource(bos.toByteArray(), "application/vnd.ms-excel");
MimeBodyPart attachment = new MimeBodyPart();
attachment.setFileName(MimeUtility.encodeText("테스트파일_" + nowStr, "UTF-8","B")); // 파일이름설정
attachment.setDataHandler(new DataHandler(fds)); // 전달파일 핸들러
//멀티파트 형식으로 파일정보 추가
mp.addBodyPart(attachment);
//메일 전달내용에 해당 멀티파트(엑셀파일) 정보 추가
mimeMessage.setContent(mp);
System.out.println(" ===== file info setting end ===== ");
//메일 발송
System.out.println(" ===== file info setting end ===== ");
transport.connect("smtp.gmail.com", SendId, SendPw);;
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
} catch (AddressException ae) {
System.out.println("AddressException : " + ae);
return "fail";
} catch (MessagingException me) {
System.out.println("MessagingException : " + me);
return "fail";
} catch (UnsupportedEncodingException e) {
System.out.println("UnsupportedEncodingException : " + e);
return "fail";
}finally {
try {
transport.close();
System.out.println("After Mail Send [transport Close Success]");
} catch (MessagingException e) {
System.out.println("메일 세션 종료 오류 발생 " + e);
}
}
return "success";
}
public Workbook makeEmailFormatListExcel(List<Map<String, String>> emailFormatList) {
Workbook wb = new XSSFWorkbook();
System.out.println("emailFormatList size -> "+ emailFormatList.size());
Sheet sheet = wb.createSheet("info");
int rownum = 0;
int cellnum = 0;
Row row = sheet.createRow(rownum++);
row.createCell(cellnum++).setCellValue("테스트이름");
row.createCell(cellnum++).setCellValue("테스트나이");
//데이터 루프 문 시작 가져온 데이터 만큼 반복
for(Map<String, String> emailFormatInfo: emailFormatList) {
System.out.println("emailFormatInfo -> " + emailFormatInfo.toString());
row = sheet.createRow(rownum++);
cellnum = 0;
row.createCell(cellnum++).setCellValue(emailFormatInfo.get("testName"));
row.createCell(cellnum++).setCellValue(emailFormatInfo.get("testAge"));
}
System.out.println("email info file make end");
return wb;
}
}
3. 컨트롤러
컨트롤러에서 실제 테스트를 돌려 볼 수 있게끔 구성하였다.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class TestController {
@GetMapping("/test/mail/send")
public void testMail() {
String id = "보내는사람아이디"; //ex) test@test.com
String pw = "보내는사람비밀번호";
//https://myaccount.google.com/lesssecureapps
//해당 링크에서 보안 수준이 낮은 앱 엑세스 허용
//발송자 인증객체 생성
MailAuthUtil mailAuthUtil = new MailAuthUtil(id, pw);
//메일 발송을 위한 객체 생성
MailSendUtil MailSendUtil = new MailSendUtil();
//엑셀파일 생성을 위한 리스트 해쉬맵 객체 생성
Map<String, String> map1 = new HashMap<String, String>();
map1.put("testName", "test1");
map1.put("testAge", "99");
Map<String, String> map2 = new HashMap<String, String>();
map2.put("testName", "test2");
map2.put("testAge", "100");;
List<Map<String, String>> list = new ArrayList<Map<String,String>>();
list.add(map1);
list.add(map2);
//엑셀파일 생성
Workbook wb = MailSendUtil.makeEmailFormatListExcel(list);
//수신자 정보 설정
String title = "테스트 제목 메일입니다.";
String content = "테스트 내용 메일입니다.";
String recevier ="받는사람이메일주소"; //ex) test@test.com
String result = "";
//메일발송
result = MailSendUtil.mailSend(mailAuthUtil, recevier, content, title, wb);
System.out.println("mail send -> " + result);
}
}
//https://myaccount.google.com/lesssecureapps
//해당 링크에서 보안 수준이 낮은 앱 엑세스 허용
위의 주석을 참고해서 아래와 같이 보안 수준이 낮은 앱의 액세스를 허용해주어야 한다. 해당 액세스는 발송자 이메일 계정에서 설정해야 한다.(설정 안하면 메일 발송 안됨 -> 인증 과정에 막히게 된다.)
메인 이미지 출처 : Photo by Camilo Contreras on Unsplash