[JAVA] GMAIL 연동하여 메일 보내기

김나영·2023년 4월 20일
1

JAVA

목록 보기
14/14
post-thumbnail

다행스럽게도 학원에서 배웠던 코드가 있어서 해당 코드 참고 + chatGPT의 도움으로 코드를 짰다.

학원코드

	// 이메일을 보내는 사용자 정보
	@Value(value = "${mail.username}")
	private String username;  // 본인 지메일 주소
	@Value(value="${mail.password}")
	private String password;  // 발급 받은 앱 비밀번호	
    @Override		// 인증코드 발송
	public Map<String, Object> sendAuthCode(String email) {
		// 인증코드 만들기
		// String authCode = securityUtil.generateRandomString(6);		// 디펜던시로 만들어주는것 (스프링이 해줌)
		String authCode = securityUtil.getAuthCode(6);		// 수동으로 만든것
		System.out.println("발송된 인증코드 : " + authCode);		
		// 이메일 전송을 위한 필수 속성을 properties 객체로 생성
		Properties properties = new Properties();
		properties.put("mail.smtp.host", "smtp.gmail.com");			// 구글 메일로 보냄 (보내는 메일은 구글메일만 가능)
		properties.put("mail.smtp.port", "587");					// 구글 메일로 보내는 포트 번호
		properties.put("mail.smtp.auth", "true");					// 인증된 메일
		properties.put("mail.smtp.starttls.enable","true");			// TLS 허용
			이메일 보내기 API 사용을 위한 사전 작업		
			1. 구글 로그인
			2. Google계정 - 보안
				1) 2단계 인증 	- 사용
				2) 앱 비밀번호
					(1) 앱 선택   : 기타
					(2) 기기 선택 : Windows 컴퓨터
					(3) 생성 버튼 : 16자리 앱 비밀번호를 생성해 줌 (이 비밀번호를 이메일 보낼 때 사용) 	
		// 사용자 정보를 javax.mail.Session에 저장
		Session session = Session.getInstance(properties, new Authenticator() {
			@Override
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(username, password);
			}
		});	
		// 이메일 작성 및 전송
		try {
			Message message = new MimeMessage(session);			
			message.setFrom(new InternetAddress(username, "인증코드관리자"));		// 보내는 사람
			message.setRecipient(Message.RecipientType.TO, new InternetAddress(email));			// setRecipients 는 여러사람에게 보낼때 사용  // 받는사람
			message.setSubject("[Application] 인증 요청 메일입니다.");				// 제목
			message.setContent("인증번호는 <strong>" + authCode + "</strong>입니다.", "text/html; charset=UTF-8");		// 내용			
			Transport.send(message);		// 이메일 전송			
		} catch (Exception e) {
			e.printStackTrace();
		}		
		// join.jsp로 반환할 데이터
		// 생성한 인증코드를 보내줘야 함
		// 그래야 사용자가 입력한 인증코드와 비교를 할 수 있음
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("authCode", authCode);
		return result;
	}

완성된 코드

private static String type = "text/html; charset=utf-8";
private static String emailAdd = "보내는사람메일주소";
private static String password = "앱비밀번호";
private static String to = "받는사람메일주소";
	public static void sendEmail(String host, String input, String usePercent ) {
		Properties properties = new Properties();
		properties.put("mail.smtp.host", "smtp.gmail.com");
		properties.put("mail.smtp.port", 587);
		properties.put("mail.smtp.auth", "true");
		properties.put("mail.smtp.starttls.enable","true");
		properties.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");		
		Authenticator auth = new Authenticator() {
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(emailAdd, password);
			}
		};		
		Session session = Session.getInstance(properties, auth);		
		try {
			Message message = new MimeMessage(session);
			message.setFrom(new InternetAddress(emailAdd,"발신자이름"));
			message.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
			message.setSubject("[용량초과알림] " + input + " 용량 초과");
			message.setContent( "호스트 : " + host + "<br>"+ input + " 파티션의 용량이 80%를 초과하였습니다. <br>  현재 용량 : " + usePercent + "%", type);			
			Transport.send(message);			
			System.out.println("용량 초과 안내 메일 발송");			
		}catch (Exception e) {
			e.printStackTrace();
		}		
	}

오류

javax.mail.MessagingException: Can't send command to SMTP host;
nested exception is:
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)

해당 오류는 TLS 프로토콜을 사용하지 못해서 발생하는 오류라고 지피티가 알려줘따.
이 오류를 해결하기 위해서는 SSLv3, TLSv1, TLSv1.1을 사용하지 않도록 설정해야 한다.

구글링해서 보면 jre의 java.security 파일에서 해당 부분을 삭제하고 저장하면 된다고 하던데 나는 권한이 되지 않아서 파일 수정이 불가했다.

  • SSL 프로토콜을 사용하게 환경 설정하는 방법

그래서 지피티가 알려준대로 코드를 추가했다.

  • 추가코드
    properties.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");

하지만 코드를 추가해도 메일이 보내지지 않았고 ㅠㅠ 또다른 오류가 발생했다

javax.mail.authenticationfailedexception: 534-5.7.9 application-specific password required. learn more at 534 5.7.9 https://support.google.com/mail/?p=invalidsecondfactor z17-20020a17090a541100b0024739d29252sm6526007pjh.15 - gsmtp

비밀번호가 잘못 입력된 경우 발생하는 오류인데 알보고니
'앱 비밀번호' 가 아닌... 내 이메일 비밀번호를 적어놓은거였다,,!!!
ㅎㅎㅋㅋ..ㅋㅋ~!!!!!

앱 비밀번호를 다시 발급받아 맞게 넣으니 잘 돌아갔음..

마지막으로 반드시 확인해야하는 사항 중 하나는
pom.xml에 추가한 dependency의 버전!
처음에는 구글링한대로 나온 1.4 를 넣었는데도 안되어서
학원에서 배운대로 버전을 변경해줬더니 너무 잘 돌아갔었다,,
버전 체크 필수..!!!

  • pom.xml
    <dependency>
      <groupId>com.sun.mail</groupId>
      <artifactId>javax.mail</artifactId>
      <version>1.6.2</version>
    </dependency>

코드 뜯어보기

  • properties
    SMTP 프로토콜을 사용하여 이메일을 보내기 위한 설정 정보를 담음.
    put() 메소드를 사용하여 설정 정보를 추가.
    mail.smtp.host, mail.smtp.port, mail.smtp.auth, mail.smtp.starttls.enable, mail.smtp.ssl.protocols
  • Authenticator
    추상클래스로, 이메일 인증 정보를 제공하는 클래스
    SMTP 프로토콜을 사용하여 이메일을 보낼 때, 보안상의 이유로 보내는 사람의 이메일 주소와 비밀번호를 제공해야 한다. 이 정보를 제공하지 않으면 SMTP 서버에서 이메일을 보낼 수 없음
    Authenticator 객체는 Session 객체를 생성할 때 인자로 전달. 이 객체는 SMTP 서버에 접속할 때 보안 인증을 처리하는 데 사용.
    Authenticator 클래스를 상속받은 익명 클래스를 생성하여, getPasswordAuthentication() 메소드를 오버라이딩하여 발신자 이메일 주소화 비밀번호를 반환.
    Authenticator auth = new Authenticator() : 객체를 생성하고, 익명 클래스를 사용하여 발신자의 이메일 주소화 비밀번호를 제공하는 코드를 작성. 이후 Session객체를 생성할 때 이 Authenticator 객체를 전달하여 SMTP 세션에 인증 정보 제공.
  • Session
    이메일 세션을 나타내는 객체. Session.getInstance() 메소드를 사용하여 Session 객체를 생성할 수 있음. 이 때, 메소드의 인자로 SMTP 서버 설정 정보가 담긴 properties 객체와 인증 정보를 제공하는 Authenticator 객체를 전달함.
    Session 객체는 이메일 발송에 필요한 정보를 담고 있음. SMTP 서버 설정 정보, 발신자 이메일 주소, 수신자 이메일 주소, 이메일 제목, 내용 등
    Session.getInstance(properties, auth): SMTP 서버 설정 정보와 인증 정보를 제공하여 Session 객체를 생성.

  • TLS의 포트 번호는 587 / SSL의 포트 번호는 465
    구글의 경우 587이고 네이버는 465이다
profile
응애 나 애기 개발자

0개의 댓글