<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jjaeeeee_1.log</title>
        <link>https://velog.io/</link>
        <description>피곤해도 버텨야지 뭐 어쩌겠어</description>
        <lastBuildDate>Mon, 09 Sep 2024 06:37:39 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jjaeeeee_1.log</title>
            <url>https://velog.velcdn.com/images/jjaeeeee_1/profile/040571d2-a16f-4dfe-9891-501b7fb287f1/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jjaeeeee_1.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jjaeeeee_1" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Kotlin] Spring Boot로 메일(Gmail) 발송하기]]></title>
            <link>https://velog.io/@jjaeeeee_1/Kotlin-Spring-Boot%EB%A1%9C-%EB%A9%94%EC%9D%BCGmail-%EB%B0%9C%EC%86%A1%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jjaeeeee_1/Kotlin-Spring-Boot%EB%A1%9C-%EB%A9%94%EC%9D%BCGmail-%EB%B0%9C%EC%86%A1%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 09 Sep 2024 06:37:39 GMT</pubDate>
            <description><![CDATA[<p>유저가 메일 발송 요청을 했을 때, 운영자(관리자)에게 <code>상세 구매 및 사용 내역</code> 메일을 요청할 때 운영자에게 자동으로 알림을 보내는 기능을 구현할 것이다.</p>
<h2 id="기능-개요">기능 개요:</h2>
<blockquote>
<ol>
<li>유저가 웹사이트에서 &#39;상세 구매 및 사용 내역&#39; 메일을 요청 (메일 발송 요청 클릭)</li>
<li>운영자에게 알림 메일을 보냄</li>
<li>알림 메일에는 <code>&quot;홍길동님이 상세 구매 및 사용 내역 메일 발송 요청을 했습니다.&quot;</code> 와 같은 메시지 포함</li>
</ol>
</blockquote>
<br>

<h2 id="개발-환경">개발 환경</h2>
<blockquote>
<p>Kotlin: v 1.9.23
SpringBoot: v 3.2.5</p>
</blockquote>
<h3 id="gradle-의존성-추가-buildgradle">Gradle 의존성 추가 (build.gradle)</h3>
<pre><code>implementation(&quot;org.springframework.boot:spring-boot-starter-mail&quot;)</code></pre><h3 id="환경-변수-설정">환경 변수 설정</h3>
<p>운영자의 이메일 주소를 환경 변수에 저장
application.yml나 properties에 파일에 아래 코드를 추가:</p>
<p><code>application.yml</code>:</p>
<pre><code>spring
    mail:
        host: smtp.gmail.com
        port: 587
        username: 실제 Gmail
        password: 구글 계정 비밀번호 or 2단계 인증 앱 비밀번호
        properties:
            mail:
                smtp:
                    auth: true
                    starttls:
                        enable: true

notification:
    email: 실제 Gmail(운영자(관리자) 메일)</code></pre><p><code>application.properties</code>:</p>
<pre><code>notification.email=operator@example.com(실제 Gmail)

# 메일 서버 설정
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=your-email@gmail.com(실제 Gmail)
spring.mail.password=your-password(구글 계정 비밀번호 or 2단계 인증 앱 비밀번호)
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true</code></pre><br>

<h3 id="mailsenderconfig">MailSenderConfig</h3>
<blockquote>
<p>MailSenderConfig가 뭐냐고?</p>
</blockquote>
<p>MailSenderConfig는 스프링에서 이메일 발송 설정하는 클래스임
이거 없으면 이메일 못 보내니까 중요함!</p>
<h4 id="이-클래스가-하는-일은">이 클래스가 하는 일은?</h4>
<ul>
<li>이메일 보내는 데 필요한 설정 다 해줌</li>
<li><code>JavaMailSender</code>라는 <code>Bean</code>을 만들어서 스프링한테 줌</li>
</ul>
<h4 id="왜-이런-게-필요한데">왜 이런 게 필요한데?</h4>
<ul>
<li>이메일 보내는 설정을 따로 관리하면 편함</li>
<li>설정 바꾸고 싶을 때 여기만 바꾸면 됨</li>
<li>보안 설정도 여기서 다 할 수 있음</li>
</ul>
<p><code>MailSenderConfig</code>:</p>
<p>import문은 버전 마다 달라서 넣지 않음</p>
<pre><code>@Configuration
class MailSenderConfig {

    @Value(&quot;\${spring.mail.host}&quot;)
    private lateinit var host: String

    @Value(&quot;\${spring.mail.port}&quot;)
    private lateinit var port: String

    @Value(&quot;\${spring.mail.username}&quot;)
    private lateinit var username: String

    @Value(&quot;\${spring.mail.password}&quot;)
    private lateinit var password: String

    @Bean
    fun javaMailSender(): JavaMailSender {
        val mailSender = JavaMailSenderImpl()
        mailSender.host = host
        mailSender.port = port.toInt()
        mailSender.username = username
        mailSender.password = password

        val props: Properties = mailSender.javaMailProperties
        props[&quot;mail.transport.protocol&quot;] = &quot;smtp&quot;
        props[&quot;mail.smtp.auth&quot;] = &quot;true&quot;
        props[&quot;mail.smtp.starttls.enable&quot;] = &quot;true&quot;
        props[&quot;mail.debug&quot;] = &quot;true&quot;

        return mailSender
    }
}</code></pre><h3 id="emailservice">EmailService</h3>
<p>예시 코드이므로 상황에 맞게 코드 수정이 필요함</p>
<pre><code>@Service
class EmailService(private val emailSender: JavaMailSender) {

    @Value(&quot;\${operator.email}&quot;)
    private lateinit var operatorEmail: String

    fun sendNotificationEmail(userEmail: String) {
        val message = SimpleMailMessage()
        message.setFrom(&quot;noreply@example.com&quot;)
        message.setTo(operatorEmail)
        message.setSubject(&quot;사용자 메일 발송 요청 알림&quot;)
        message.setText(&quot;$userEmail 님이 상세 구매 및 사용 내역 메일 발송 요청을 했습니다.&quot;)
        emailSender.send(message)
    }
}</code></pre><h3 id="emailcontroller">EmailController</h3>
<p>예시 코드이므로 상황에 맞게 코드 수정이 필요함</p>
<pre><code>@RestController
class UserController(private val emailService: EmailService) {

    @PostMapping(&quot;send-email&quot;)
    fun sendEmailRequest(
    // 사용자 인증 과정이 필요(ex. SpringSecurity)
      ): String {
      // 사용자 인증 과정이 필요(ex. SpringSecurity)
        return emailService.sendNotificationEmail(request.email)
    }
}</code></pre><h2 id="구글-계정-정보를-잘-입력했는데-이슈가-">구글 계정 정보를 잘 입력했는데 이슈가 ?</h2>
<pre><code>DEBUG SMTP: Attempt to authenticate using mechanisms: LOGIN ... XOAUTH2 
DEBUG SMTP: Using mechanism LOGIN
DEBUG SMTP: AUTH LOGIN command trace suppressed
DEBUG SMTP: AUTH LOGIN failed
10:26:23.0208 [ERROR] [com...common.exception.GlobalExceptionHandler] Authentication failed
 org.springframework.mail.MailAuthenticationException: Authentication failed</code></pre><p>Google 계정 로그인할 때 사용하는 비밀번호를 입력하고 메일 발송 요청을 하게 되면 아래와 같은 이슈가 발생함 </p>
<p>인증에 실패했다는 메시지로 해석됨</p>
<p>해결 방법에는 2단계 인증을 설정하고 앱 비밀번호를 만들어 구글 계정 비밀번호 대신 앱 비밀번호를 입력하는 방법이 있음</p>
<h3 id="google-계정-설정-gmail-설정">Google 계정 설정, Gmail 설정</h3>
<blockquote>
<p>앱 비밀번호를 등록하려면 2단계 인증이 필요함</p>
</blockquote>
<ol>
<li><p>구글 계정 관리
<img src="https://velog.velcdn.com/images/jjaeeeee_1/post/e212ecff-afc0-4837-88a4-e6b142063fa2/image.png" alt=""></p>
</li>
<li><p>보안 &gt; 2단계 인증 설정
<img src="https://velog.velcdn.com/images/jjaeeeee_1/post/285bc569-7266-4226-9ac4-fa8c16cb5f98/image.png" alt=""></p>
</li>
<li><p>2단계 인증 설정 후 앱 비밀번호 생성
<img src="https://velog.velcdn.com/images/jjaeeeee_1/post/fc901d0a-d7e6-477f-9dc7-025c788b4338/image.png" alt=""></p>
</li>
</ol>
<ul>
<li>앱 비밀번호를 검색한 후 앱 비밀번호 생성, 앱 비밀번호 키 저장</li>
<li><code>application.yml</code> 이나 <code>properties</code>의 <code>password</code>에 복사 붙여넣기</li>
</ul>
<p><br><br><br><br></p>
<p>비밀번호나 민감한 정보는 코드에 직접 쓰지 말고 환경 변수로 빼는 게 더 안전함
이메일 보내기 설정 완료!</p>
]]></description>
        </item>
    </channel>
</rss>