본문 바로가기

[IT/Programming]/HTML related

Email by JAVA (자바 프로그램을 이용해 이메일 보내기)

반응형
# Email by JAVA (자바 프로그램을 이용해 이메일 보내기, javax.mail.jar) 이메일 (Email) 을 프로그래밍적으로 보내고 싶은데 어떻게 해야할까? 메일로 광고/스팸 메일 받는걸 엄청 싫어하기 때문에, 이런건 공개 안하는게 좋을거 같기도?ㅋ 개인적으로는 Recoeve.net 에 회원가입을 할 때, 계정 만들고 이메일 통해 인증/확인 하기 위한 용도로 이메일을 활용하려고 하는 중인데, 또 비밀번호를 잊어버렸다거나 했을때의 보완수단으로서 활용하려고... 이러려면 아무튼 프로그래밍적으로 이메일을 보낼 수 있어야 한다. 어떻게 하면 될까? ## TOC ## Email Server 만들기 아예 Email Server 까지 돌리면서 JAVA 랑 연결해서 자동화 시키는 방법도 있는거 같긴한데... 귀찮;;; 방법은 알아서 찾아보시길. 시간날때 정리하겠음; (아예 안할지도ㅋ) ## 네이버 메일 by 자바 (Naver mail by JavaMail) 우선 에서 javax.mail.jar file 을 다운받읍시다. 적당한 폴더에 넣어놓고, 이 폴더\javax.mail.jar 를 윈도우 변수(?) CLASSPATH 에 포함시킵시다. 아니면 java compile 하거나 실행시킬때, javac -classpath "folder path\javax.mail.jar;other classes", java -classpath "folder path\javax.mail.jar;other classes" 식으로 실행시키면 됨. 그리고 아래와 같이 JAVA 코드를 작성하면 잘 돌아감. 해당 코드는 에서 가져왔고, 제가 class 이름 등 약간 수정함. 아래와 같은 코드로 잘 동작했었는데, 최근에 뭔가 바뀐건지 AWS server 에서는 잘 동작을 안함. Error 잡는 중. 혹시 아시는 분 있으면 도와주세요~!
AWS 의 Outbound rule (아웃바운드 규칙) 을 잘 설정해줘야 했었음. SMTP port 가 587 을 기본적으로 이용하던데, 기존의 Outbound rule 에서는 1024 - 65XXX 까지 포트만 열어놨었어서 timeout 이 발생한 것인듯. 친구 구경렬의 도움으로 해!결! 땡큐~!
```[.scrollable.lang-java] package recoeve.http; import com.sun.mail.smtp.*; // import java.security.Security; // import java.util.Date; import java.util.Properties; import javax.mail.*; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; // For import: download javax.mail.jar file from Java.net - The Source for Java Technology Collaboration - JavaMail API // and include the filepath in classpath. // C:\Recoeve\classes\javax.mail.jar // API: Package com.sun.mail.smtp // https://javamail.java.net/nonav/docs/api/com/sun/mail/smtp/package-summary.html // https://developers.google.com/appengine/docs/java/mail/usingjavamail /** * https://stackoverflow.com/questions/3649014/send-email-using-java * asked Sep 6 '10 at 4:34 by Mohit Bansal * @author doraemon */ public class NaverMail{ public static void sendChangePwd(String id, String email, String token, String lang) throws AddressException, MessagingException { String title="Forgot password on Recoeve.net?"; if (lang.equals("ko")) { title="Recoeve.net 의 비밀번호를 잊어버리셨나요?"; } String url="https://"+Recoeve.HOST+"/account/changePwd?id="+id+"&email="+email+"&token="+token; String msg="<span style='line-height:1.6; font-family:'Malgun Gothic', '맑은 고딕', 나눔고딕, NanumGothic, Tahoma, Sans-serif; font-size:27px'>Within 10 minutes after you receive this email, please visit<br><a href='"+url+"&lang=en"+"'>"+url+"&lang=en"+"</a>.<br><br><br><br>이메일을 받으신 후 10분내로 다음 링크를 방문해주세요.<br><a href='"+url+"&lang=ko"+"'>"+url+"&lang=ko"+"</a></span>"; NaverMail.send(email, "", title, msg); } public static void sendVeriKey(String email, String id, String veriKey) throws AddressException, MessagingException { String title="Verify your account on Recoeve.net"; String url="https://"+Recoeve.HOST+"/account/verify/"+id+"/"+veriKey; String msg="<span style='line-height:1.6; font-family:'Malgun Gothic', '맑은 고딕', 나눔고딕, NanumGothic, Tahoma, Sans-serif; font-size:27px'>Thanks for your registration on <a href='https://recoeve.net/'>Recoeve.net</a>.<br><br>Please log in <a href='https://recoeve.net/'>Recoeve.net</a> first, and then click the following link to verify your account:<br><a href='"+url+"'>"+url+"</a><br><br><br><br><a href='https://recoeve.net/'>Recoeve.net</a> 가입을 환영합니다.<br><br>계정 이메일 인증을 위해 로그인 후 다음 링크를 클릭해 주세요.:<br><a href='"+url+"'>"+url+"</a><br></span>"; NaverMail.send(email, "", title, msg); } private static final String username="kipid84"; private static final String amho="amho"; private static final Properties prop = new Properties(); static { prop.put("mail.smtp.host", "smtp.naver.com"); prop.put("mail.smtp.port", "587"); prop.put("mail.smtp.auth", "true"); prop.put("mail.smtp.starttls.enable", "true"); // TLS } private static final Session session = Session.getInstance( prop, new javax.mail.Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, amho); } } ); /** * Send email using NaverMail SMTP server. * * @param recipientEmail TO recipient * @param ccEmail CC recipient. Can be empty if there is no CC recipient * @param title title of the message * @param message message to be sent * @throws AddressException if the email address parse failed * @throws MessagingException if the connection is dead or not in the connected state or if the message is not a MimeMessage */ public static void send(String recipientEmail, String ccEmail, String title, String message) throws AddressException, MessagingException { try { Message msg = new MimeMessage(session); msg.setFrom(new InternetAddress("kipid84@naver.com")); msg.setRecipients( Message.RecipientType.TO, InternetAddress.parse(recipientEmail) ); msg.setSubject(title); msg.setContent(message, "text/html; charset=utf-8"); Transport.send(msg); } catch (MessagingException e) { e.printStackTrace(); } } public static void main(String... args) throws Exception { NaverMail.sendVeriKey("kipid84@naver.com", "kipid", "dfij378asd91fa9sdf1kraq9defr134nr913hjred9af"); NaverMail.sendChangePwd("kipid", "kipid84@naver.com", "29riw7fus8dfu8348u48f8uf", "ko"); } } ```/ ### Error in AWS server Windows firewall 도 다 열어보고 별 짓을 다 해 봤는데도 해결이 안됨 ㅡ,.ㅡ;;; Security 어쩌구에서 뭔가 막고 있나???
AWS Windows Server specification/version
```[.scrollable.lang-java] Compiling NaverMail.java --- OUTPUT: recoeve.http.NaverMail --- com.sun.mail.util.MailConnectException: Couldn't connect to host, port: smtp.naver.com, 587; timeout -1; nested exception is: java.net.ConnectException: Connection timed out: connect at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2209) at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:740) at javax.mail.Service.connect(Service.java:388) at javax.mail.Service.connect(Service.java:246) at javax.mail.Service.connect(Service.java:195) at javax.mail.Transport.send0(Transport.java:254) at javax.mail.Transport.send(Transport.java:124) at recoeve.http.NaverMail.send(NaverMail.java:90) at recoeve.http.NaverMail.sendVeriKey(NaverMail.java:47) at recoeve.http.NaverMail.main(NaverMail.java:97) Caused by: java.net.ConnectException: Connection timed out: connect at java.base/sun.nio.ch.Net.connect0(Native Method) at java.base/sun.nio.ch.Net.connect(Net.java:580) at java.base/sun.nio.ch.Net.connect(Net.java:569) at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:576) at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) at java.base/java.net.Socket.connect(Socket.java:666) at java.base/java.net.Socket.connect(Socket.java:600) at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:359) at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:238) at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2175) ... 9 more com.sun.mail.util.MailConnectException: Couldn't connect to host, port: smtp.naver.com, 587; timeout -1; nested exception is: java.net.ConnectException: Connection timed out: connect at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2209) at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:740) at javax.mail.Service.connect(Service.java:388) at javax.mail.Service.connect(Service.java:246) at javax.mail.Service.connect(Service.java:195) at javax.mail.Transport.send0(Transport.java:254) at javax.mail.Transport.send(Transport.java:124) at recoeve.http.NaverMail.send(NaverMail.java:90) at recoeve.http.NaverMail.sendChangePwd(NaverMail.java:39) at recoeve.http.NaverMail.main(NaverMail.java:98) Caused by: java.net.ConnectException: Connection timed out: connect at java.base/sun.nio.ch.Net.connect0(Native Method) at java.base/sun.nio.ch.Net.connect(Net.java:580) at java.base/sun.nio.ch.Net.connect(Net.java:569) at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:576) at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) at java.base/java.net.Socket.connect(Socket.java:666) at java.base/java.net.Socket.connect(Socket.java:600) at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:359) at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:238) at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2175) ... 9 more [Finished in 48.8s] ```/ ### Error in Vert.x server running on AWS now. ```[.scrollable.lang-java] com.sun.mail.util.MailConnectException: Couldn't connect to host, port: smtp.naver.com, 587; timeout -1; nested exception is: java.net.ConnectException: Connection timed out: connect at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2209) at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:740) at javax.mail.Service.connect(Service.java:388) at javax.mail.Service.connect(Service.java:246) at javax.mail.Service.connect(Service.java:195) at javax.mail.Transport.send0(Transport.java:254) at javax.mail.Transport.send(Transport.java:124) at recoeve.http.NaverMail.send(NaverMail.java:90) at recoeve.http.NaverMail.sendChangePwd(NaverMail.java:39) at recoeve.db.RecoeveDB.forgotPwd(RecoeveDB.java:784) at recoeve.http.Recoeve.lambda$start$16(Recoeve.java:594) at io.vertx.core.impl.future.FutureImpl$1.onSuccess(FutureImpl.java:91) at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:60) at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:211) at io.vertx.core.impl.future.PromiseImpl.tryComplete(PromiseImpl.java:23) at io.vertx.core.http.impl.HttpEventHandler.handleEnd(HttpEventHandler.java:79) at io.vertx.core.http.impl.Http2ServerRequest.handleEnd(Http2ServerRequest.java:198) at io.vertx.core.http.impl.Http2ServerStream.handleEnd(Http2ServerStream.java:198) at io.vertx.core.http.impl.VertxHttp2Stream.lambda$new$1(VertxHttp2Stream.java:62) at io.vertx.core.streams.impl.InboundBuffer.handleEvent(InboundBuffer.java:255) at io.vertx.core.streams.impl.InboundBuffer.write(InboundBuffer.java:134) at io.vertx.core.impl.EventLoopContext.emit(EventLoopContext.java:55) at io.vertx.core.impl.DuplicatedContext.emit(DuplicatedContext.java:158) at io.vertx.core.http.impl.VertxHttp2Stream.onEnd(VertxHttp2Stream.java:140) at io.vertx.core.http.impl.Http2ServerStream.onEnd(Http2ServerStream.java:123) at io.vertx.core.http.impl.VertxHttp2Stream.onEnd(VertxHttp2Stream.java:135) at io.vertx.core.http.impl.Http2ConnectionBase.onDataRead(Http2ConnectionBase.java:317) at io.vertx.core.http.impl.Http2ServerConnection.onDataRead(Http2ServerConnection.java:44) at io.netty.handler.codec.http2.Http2FrameListenerDecorator.onDataRead(Http2FrameListenerDecorator.java:36) at io.netty.handler.codec.http2.Http2EmptyDataFrameListener.onDataRead(Http2EmptyDataFrameListener.java:49) at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder$FrameReadListener.onDataRead(DefaultHttp2ConnectionDecoder.java:307) at io.netty.handler.codec.http2.DefaultHttp2FrameReader.readDataFrame(DefaultHttp2FrameReader.java:415) at io.netty.handler.codec.http2.DefaultHttp2FrameReader.processPayloadState(DefaultHttp2FrameReader.java:250) at io.netty.handler.codec.http2.DefaultHttp2FrameReader.readFrame(DefaultHttp2FrameReader.java:159) at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder.decodeFrame(DefaultHttp2ConnectionDecoder.java:173) at io.netty.handler.codec.http2.DecoratingHttp2ConnectionDecoder.decodeFrame(DecoratingHttp2ConnectionDecoder.java:63) at io.netty.handler.codec.http2.Http2ConnectionHandler$FrameDecoder.decode(Http2ConnectionHandler.java:393) at io.netty.handler.codec.http2.Http2ConnectionHandler.decode(Http2ConnectionHandler.java:453) at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:529) at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:468) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290) at io.vertx.core.http.impl.VertxHttp2ConnectionHandler.channelRead(VertxHttp2ConnectionHandler.java:416) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1383) at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1246) at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1295) at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:529) at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:468) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:290) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:1623) Caused by: java.net.ConnectException: Connection timed out: connect at java.base/sun.nio.ch.Net.connect0(Native Method) at java.base/sun.nio.ch.Net.connect(Net.java:580) at java.base/sun.nio.ch.Net.connect(Net.java:569) at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:576) at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) at java.base/java.net.Socket.connect(Socket.java:666) at java.base/java.net.Socket.connect(Socket.java:600) at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:359) at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:238) at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2175) ... 66 more ```/ ## Gmail (지메일) by JavaMail (Old version)
2023-06-18 : 이 섹션은 오래된 문서입니다. 최근 구글에서는 외부에서 이메일을 못보내게 막았던걸로 기억하네요. 그래서 이 방법으로 Gmail 은 못보내는걸로 압니다.
Gmail 에서 JAVA 프로그래밍을 통한 이메일을 보내려면 계정설정에서 계정 설정 - 보안 수준이 낮은 앱의 엑세스 를 허용해야 하는듯. 그런데 보안 높이려면 어찌해야 하지? ㅡㅂㅡ
Email Server 까지 만들기는 귀찮으니 많이들 사용하는 Gmail 계정을 JAVA 와 연결해서 메일을 보내는 법을 알아봅시다. 우선 에서 javax.mail.jar file 을 다운받읍시다. 적당한 폴더에 넣어놓고, 이 폴더\javax.mail.jar 를 윈도우 변수(?) CLASSPATH 에 포함시킵시다. 아니면 java compile 하거나 실행시킬때, javac -classpath "folder path\javax.mail.jar;other classes", java -classpath "folder path\javax.mail.jar;other classes" 식으로 실행시키면 됨. 그리고 아래와 같이 JAVA 코드를 작성하면 잘 돌아감. 해당 코드는 에서 가져왔고, 제가 class 이름 등 약간 수정함. ```[.scrollable.lang-java] import com.sun.mail.smtp.SMTPTransport; import java.security.Security; import java.util.Date; import java.util.Properties; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; // For import: download javax.mail.jar file from Java.net - The Source for Java Technology Collaboration - JavaMail API // and include the filepath in classpath. // API: Package com.sun.mail.smtp // https://javamail.java.net/nonav/docs/api/com/sun/mail/smtp/package-summary.html // https://developers.google.com/appengine/docs/java/mail/usingjavamail /** * http://stackoverflow.com/questions/3649014/send-email-using-java * asked Sep 6 '10 at 4:34 by Mohit Bansal * @author doraemon */ public class Gmail{ public static void main(String... args) throws Exception { // Test Gmail.send("gmail id", "gmail password", "to email", "cc email", "title", "msg"); } /** * Send email using GMail SMTP server. * * @param username GMail username * @param password GMail password * @param recipientEmail TO recipient * @param ccEmail CC recipient. Can be empty if there is no CC recipient * @param title title of the message * @param message message to be sent * @throws AddressException if the email address parse failed * @throws MessagingException if the connection is dead or not in the connected state or if the message is not a MimeMessage */ public static void send(final String username, final String password, String recipientEmail, String ccEmail, String title, String message) throws AddressException, MessagingException { Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory"; // Get a Properties object Properties props = System.getProperties(); props.setProperty("mail.smtps.host", "smtp.gmail.com"); props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY); props.setProperty("mail.smtp.socketFactory.fallback", "false"); props.setProperty("mail.smtp.port", "465"); props.setProperty("mail.smtp.socketFactory.port", "465"); props.setProperty("mail.smtps.auth", "true"); /* If set to false, the QUIT command is sent and the connection is immediately closed. If set to true (the default), causes the transport to wait for the response to the QUIT command. ref : http://java.sun.com/products/javamail/javadocs/com/sun/mail/smtp/package-summary.html http://forum.java.sun.com/thread.jspa?threadID=5205249 smtpsend.java - demo program from javamail */ props.put("mail.smtps.quitwait", "false"); Session session = Session.getInstance(props, null); // -- Create a new message -- final MimeMessage msg = new MimeMessage(session); // -- Set the FROM and TO fields -- msg.setFrom(new InternetAddress("noreply@recoeve.com")); // 이거 안먹힘. Does not work. (Cannot change from-email.) // msg.setFrom(new InternetAddress(username + "@gmail.com")); // 이렇게 설정하나 안하나 보낸 계정으로 from 이 정해짐. 스팸/Abusing/Cheating/속임수/사기 막으려고 이런 설정은 막아놓은듯? From 을 마음대로 바꿀 수 있으면 낚시가 너무 쉬워지긴 할듯. msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail, false)); if (ccEmail.length()>0) { msg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(ccEmail, false)); } msg.setSubject(title); msg.setContent(message, "text/html; charset=utf-8"); msg.setSentDate(new Date()); SMTPTransport t=(SMTPTransport)session.getTransport("smtps"); t.connect("smtp.gmail.com", username, password); t.sendMessage(msg, msg.getAllRecipients()); t.close(); } } ```/ ## RRA
  1. javaee.github.io/javamail :: The Source for Java Technology Collaboration - JavaMail API
    and javaee.github.io/javamail/docs/api :: API docs
    and jcp.org/en/jsr
    and https://javaee.github.io/javamail/docs/JavaMail-1.6.pdf
  2. javamail.java.net - API docs - Package com.sun.mail.smtp summary
  3. developers.google.com - Google App Engine - Java - Using JavaMail to Send Mail
  4. stackoverflow.com - Send email using java, 2010-09-06, asked by Mohit Bansal.
    // I used the answer by Cheok Yan Cheng. The code is written by doraemon (the same person??).
반응형