기존에 Yona 를 구축해서 버전관리를 잘해오고 있는데, 문제는 알림 메일이였다.
지금까지 계속 google의 SMTP로 잘 운영해오다가, 어느 순간 google의 로그인 방식이 보안 정책에 따라, OAuth 방식이 아니면 더 이상 예전 처럼 아이디/패스워드 기반의 로그인을 지원하지 않는 것이다.
그래서 naver.com 내에 계정을 하나 파서 그 안에 있는 POP3/IMAP 기능을 활성화 했고, 거기서 제공하는 SMTP 설정 값을 이용해 Yona의 application.conf 값을 아래와 같이 수정했다.
smtp.startssl = true
smtp.host = smtp.naver.com
smtp.port = 587
smtp.auth = true
#smtp.ssl = true
smtp.password = "xxxxxxx"
smtp.domain = naver.com
smtp.user = "xxxxxxx@naver.com"
설정을 변경한 뒤 Yona를 다시 시작했는데.. 왠걸.. 아래와 같은 에러가 떨어진다.
2024-03-06 13:26:51,466 - [WARN] - from application in play-akka.actor.default-dispatcher-974
Failed to send a notification: org.apache.commons.mail.HtmlEmail@1720365d
org.apache.commons.mail.EmailException: Sending the email to the following server failed : smtp.naver.com:465
at org.apache.commons.mail.Email.sendMimeMessage(Email.java:1410)
at org.apache.commons.mail.Email.send(Email.java:1437)
at info.schleichardt.play2.mailplugin.MailPlugin$$anonfun$6.apply(MailPlugin.scala:60)
at info.schleichardt.play2.mailplugin.MailPlugin$$anonfun$6.apply(MailPlugin.scala:54)
at info.schleichardt.play2.mailplugin.MailPlugin.send(MailPlugin.scala:68)
at info.schleichardt.play2.mailplugin.api.Mailer$.send(Mailer.scala:8)
at info.schleichardt.play2.mailplugin.Mailer.send(Mailer.java:15)
at controllers.ProjectApp.sendTransferRequestMail(ProjectApp.java:775)
at controllers.ProjectApp.transferProject(ProjectApp.java:634)
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$191$$anonfun$apply$191.apply(routes_routing.scala:3708)
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$191$$anonfun$apply$191.apply(routes_routing.scala:3708)
at play.core.Router$HandlerInvokerFactory$$anon$4.resultCall(Router.scala:264)
at play.core.Router$HandlerInvokerFactory$JavaActionInvokerFactory$$anon$15$$anon$1.invocation(Router.scala:255)
at play.core.j.JavaAction$$anon$1.call(JavaAction.scala:55)
at Global$2.call(Global.java:274)
at actions.AnonymousCheckAction.call(AnonymousCheckAction.java:57)
at actions.IsAllowedAction.call(IsAllowedAction.java:68)
at actions.AbstractProjectCheckAction.call(AbstractProjectCheckAction.java:93)
at play.db.ebean.TransactionalAction$1.call(TransactionalAction.java:21)
at play.db.ebean.TransactionalAction$1.call(TransactionalAction.java:18)
at com.avaje.ebeaninternal.server.core.DefaultServer.execute(DefaultServer.java:715)
at com.avaje.ebeaninternal.server.core.DefaultServer.execute(DefaultServer.java:709)
at com.avaje.ebean.Ebean.execute(Ebean.java:1264)
at play.db.ebean.TransactionalAction.call(TransactionalAction.java:18)
at play.core.j.JavaAction$$anonfun$11.apply(JavaAction.scala:82)
at play.core.j.JavaAction$$anonfun$11.apply(JavaAction.scala:82)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
at play.core.j.HttpExecutionContext$$anon$2.run(HttpExecutionContext.scala:40)
at play.api.libs.iteratee.Execution$trampoline$.execute(Execution.scala:46)
at play.core.j.HttpExecutionContext.execute(HttpExecutionContext.scala:32)
at scala.concurrent.impl.Future$.apply(Future.scala:31)
at scala.concurrent.Future$.apply(Future.scala:485)
at play.core.j.JavaAction$class.apply(JavaAction.scala:82)
at play.core.Router$HandlerInvokerFactory$JavaActionInvokerFactory$$anon$15$$anon$1.apply(Router.scala:252)
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4$$anonfun$apply$5.apply(Action.scala:130)
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4$$anonfun$apply$5.apply(Action.scala:130)
at play.utils.Threads$.withContextClassLoader(Threads.scala:21)
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4.apply(Action.scala:129)
at play.api.mvc.Action$$anonfun$apply$1$$anonfun$apply$4.apply(Action.scala:128)
at scala.Option.map(Option.scala:145)
at play.api.mvc.Action$$anonfun$apply$1.apply(Action.scala:128)
at play.api.mvc.Action$$anonfun$apply$1.apply(Action.scala:121)
at play.api.libs.iteratee.Iteratee$$anonfun$mapM$1.apply(Iteratee.scala:483)
at play.api.libs.iteratee.Iteratee$$anonfun$mapM$1.apply(Iteratee.scala:483)
at play.api.libs.iteratee.Iteratee$$anonfun$flatMapM$1.apply(Iteratee.scala:519)
at play.api.libs.iteratee.Iteratee$$anonfun$flatMapM$1.apply(Iteratee.scala:519)
at play.api.libs.iteratee.Iteratee$$anonfun$flatMap$1$$anonfun$apply$14.apply(Iteratee.scala:496)
at play.api.libs.iteratee.Iteratee$$anonfun$flatMap$1$$anonfun$apply$14.apply(Iteratee.scala:496)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:41)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:393)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Caused by: javax.mail.MessagingException: Could not connect to SMTP host: smtp.naver.com, port: 465;
nested exception is:
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1972)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:642)
at javax.mail.Service.connect(Service.java:317)
at javax.mail.Service.connect(Service.java:176)
at javax.mail.Service.connect(Service.java:125)
at javax.mail.Transport.send0(Transport.java:194)
at javax.mail.Transport.send(Transport.java:124)
at org.apache.commons.mail.Email.sendMimeMessage(Email.java:1400)
... 56 more
Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at sun.security.ssl.HandshakeContext.<init>(HandshakeContext.java:171)
at sun.security.ssl.ClientHandshakeContext.<init>(ClientHandshakeContext.java:103)
at sun.security.ssl.TransportContext.kickstart(TransportContext.java:227)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:433)
at com.sun.mail.util.SocketFetcher.configureSSLSocket(SocketFetcher.java:548)
at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:352)
at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:207)
at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1938)
... 63 more
그런데 에러를 찬찬히 살펴보니 아래와 같은 문장이 눈에 딱 띄었다.
Caused by: javax.mail.MessagingException: Could not connect to SMTP host: smtp.naver.com, port: 465;
nested exception is:
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1972)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:642)
이상해서, 과거 Yona의 Issue 창을 뒤져보니, 답글 중에 아래와 같은 답변을 발견했다.
https://github.com/yona-projects/yona/issues/746
저 내용에서 중요한 건 Stackoverflow 링크 안의 답글인데, 답글 중에,
JRE_HOME/lib/security/java.security:
파일 안에 있는
jdk.tls.disabledAlgorithms
값을 수정하면 된다는 것이다.
해결 방법
일단, 지금 운영 중인 서버의 Java 파일 중에 java.security를 찾는다.
리눅스를 기준으로 이야기하면 다음과 같이 넣으면 찾을 수 있다.
find | grep java.security
root 권한이 있어야 수정되므로 sudo 로 해당 파일을 열어준다.
그리고 jdk.tls 를 검색하면 아래와 같은 내용을 볼 수 있다.
jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \
DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \
include jdk.disabled.namedCurves
저 항목 중에 SSLv3, TLSv1, TLSv1.1 을 삭제하고 저장하도록 한다.
그러면 해결된다.