개발자의 끄적끄적

[java] SMTP프로토콜을 이용하여 메일 보내기 구현(SOCKET)[펌] 본문

개발/java & jsp

[java] SMTP프로토콜을 이용하여 메일 보내기 구현(SOCKET)[펌]

효벨 2019. 12. 29. 02:00
728x90
반응형

[java] SMTP프로토콜을 이용하여 메일 보내기 구현(SOCKET)[펌]

 

1. SMTP프로토콜이란?

컴퓨터로 E-Mail을 보낼때, sendmail이나 qmail 등의 메일서버프로그램들이 사용된다. 이 프로그램은 사용자 또는 Outlook Express와 같은

메일클라이언트와 미리 정해진 규칙들을 사용하여 메일을 발송하게 된다. 이 정해진 규칙들을 SMTP프로토콜이라고 한다.

예를 들면, 윈도우 Outlook Express를 사용하여 메일을 보내기 위해서는 계정설정을 미리 해두어야하고, 그 계정정보를 보면 "보내는 메일

서버(SMTP 서버)"라는 곳이 있다. 아웃룩 익스프레스와 이 SMTP서버가 통신을 하는데에 쓰이는 프로토콜(통신규약)이 바로 SMTP프로토콜이

다.

SMTP프로토콜은 텍스트기반의 프로토콜이기 때문에, 일반 Telnet 프로그램으로 사용이 가능하다. 즉, 텔넷으로 메일서버에 연결해서 SMTP

프로토콜에 맞도록 명령만 내려주면 바로 메일이 발송된다는 말이다.

이런 작업들을 하기 위해서는 당연히 자신이 사용하는 메일서버가 있어야 한다. 이미 Outlook Express 등의 메일클라이언트를 사용하여 메

일을 주고받을 수 있다면, 그곳에 있는 메일계정에 있는 SMTP서버의 주소를 메모해두면 된다. 그런 메일서버가 있는지 없는지를 모른다면,

SMTP, POP3서비스를 무료로 제공하는 서비스에 가입을 하면 될 것이다. 그런곳에 가입을 하면 Outlook Express 설정하는 법을 알려주는데,

이때 SMTP서버의 주소를 메모해두면 된다. 간단히 엠파스나 네이버 등에서 POP3라고 검색하면 그런 서비스업체들을 쉽게 찾을 수 있다.

 


2. SMTP프로토콜 사용해보기

이 글을 읽고, SMTP프로토콜을 구현하여 메일을 발송할때 가장 어려운 부분은 SMTP서버를 찾아서 사용하는 부분이다. 실제로 자바코드 부

분이나 SMTP프로토콜을 이해하는 것은 어렵지 않지만, 어떤 서버를 SMTP서버로 사용해야하는지를 찾아내는 것이 많이 어려울 것이다.

SMTP서버의 주소를 알고 있다면, Telnet을 사용하여 연결해보면 된다. 관례적으로 25번 포트가 SMTP포트이므로 이곳에 연결하면 된다.

"Telnet SMTP서버주소 25" 라고 연결을 하면 된다. 그렇게 하면 간단한 인사 메시지가 나올 것이다. 만일 자신의 SMTP서버 주소가

my.smtp.server.name 이라면, 다음과 같이 될 것이다.
 # telnet my.smtp.server.name 25
220 smtp.server.name SMTP Sendmail 8.11.0/8.11.0; Wed 24 Oct 2001
 


이때, 물론 my.smtp.server.name 은 그대로 치는 것이 아니라 자신의 SMTP서버주소를 적어주는 것이다. 인사 메시지가 조금씩 다를 수는

있지만, 맨 앞의 숫자가 220 이면 상관없다. 많은 종류의 프로토콜이 앞에 에러코드를 숫자로 적는식으로 대화를 한다. SMTP프로토콜에서

220은 OK라는 뜻이다. 이 에러코드는 나중에 표로 정리를 할 것이다. 아무튼 이렇게 메시지가 나오면 일단은 성공한 것이다. 연결이 되지

않는다면, 다른 SMTP서버를 찾아야만 할 것이다.

SMTP 프로토콜을 이용하는 가장 간단한 순서는 다음과 같다.

Telnet을 사용하여 25번 포트에 연결
HELO <도메인> 명령으로 인사를 한다.
MAIL FROM:<보내는사람> 명령으로 보내는 사람 지정
RCPT TO:<받는사람> 명령으로 받는 사람 지정
DATA 명령으로 본문입력을 하겠다는 의사전달
본문입력
. 를 입력하여 본문입력종료를 알림
quit 명령으로 종료
그러나 각각의 명령 다음에 에러코드와 메시지가 돌아오는것을 확인해야 하기 때문에 절차가 조금더 많을 것이다. 그럼 실제로 자신의 서

버에 연결해서 메일을 발송하면서 명령어와 에러코드 등을 살피고 절차를 확인해보도록 하자. 아래에서 220, 250 등의 숫자가 앞에 붙는

것은 사용자가 입력하는 것이 아니라, SMTP서버가 보내는 메시지이다. 따라서 사용자가 입력해야 할 부분은 이탤릭체로 되어있는 부분 뿐

이다. 또한 밑줄이 그어져 있는 부분은 그대로 입력하는 것이 아니라 자신에 맞게 입력하는 것이다. 어떤 종류의 텔넷프로그램에서는 사용

자가 입력하는 것이 보이지 않을 것이다. 그러나 입력은 되고 있는 것이므로 틀리지 않게 조심하면서 차근차근 입력하면 된다.

# telnet my.smtp.server.name 25   -- 자신의 SMTP서버를 써야 한다
220 smtp.server.name SMTP Sendmail 8.11.0/8.11.0; Wed 24 Oct 2001
helo mydomain.name   -- 자신의 컴퓨터의 도메인을 쓴다. 아무렇게나 적어도 된다.
250 pleased to meet you
mail from:sender@my.smtp.server.name -- 보내는 사람주소이다. 자신의 주소를 적는다.
250 Sender OK
rcpt to:receiver@my.mail.address -- 받는 사람주소이다. 받은 메일을 확인할 수 있는 주소를 적는다.
250 Recipient OK
data
354 Enter mail, end with "." on a line by itself
test
.
250 Message Accepted
quit
221 closing connection
 

여기까지 되었다면, 받는사람에게 메일이 발송되었는지 확인을 해본다. 제목이 없고 test 라는 본문만 있는 메일이 전송되어 있다면 성공

한 것이다. 그럼 아래는 읽지 않고 바로 3 으로 넘어가면 된다.

만일 250 Sender OK, 250 Recipient OK 라는 메시지가 오는것이 아니라, 550 Relay Denied 라는 메시지가 나올 경우, 문제는 조금 복잡해

진다. 그것은 메일서버가 스팸메일 발송을 방지하기 위한 옵션들을 설정해놓았기 때문이다. 이럴 경우에는 우선, 보내는 사람주소(mail

from: 다음에 쓰는 주소)를 바꿔본다. 예를 들면, SMTP서버 주소가 smtp.orgio.net 라면, 보내는 사람 메일 주소는 id@orgio.net 과 같이

같은 도메인에 있어야 할 것이다. 이렇게 했는데도 마찬가지의 에러가 나온다면 다른 SMTP서버를 찾아봐야 할 것이다. 그러나 아웃룩익스

프레스를 사용하여 메일이 발송되는 PC에서 작업을 하면, 이런 문제는 발생하지 않을 것이다.

 

 

 

 

3. Java 로 구현하기1 - 클래스 설계

자바로 실제로 구현하는 것은 어렵지 않다. 아까의 예제에서 손으로 입력하는 부분을 자바프로그램이 대신 입력해주면 되는 것이다. 그 역

할을 하는 클래스를 SMTPSender 라는 이름으로 만들어보자. 이 클래스에는 sendMail()이라는 메소드가 있는데, 이 메소드는 SMTP서버주소,

보내는사람주소, 받는사람주소, 내용을 파라미터로 받아서, 메일을 전송하는 메소드이다. 뭐, 좋은 설계는 아니지만, 그냥 그렇게 만들도

록 하자. 그리고 이 메소드를 main 메소드에서 적당한 값을 넣어서 불러주면 될 것이다.

또한 sendMail()메소드는 특별히 클래스멤버변수들을 사용할 필요가 없으니까, static 메소드로 작성한다. 일단 클래스를 작성해보자. 화

일 이름은 당연히 SMTPSender.java 가 될 것이다.
 // SMTPServer.java
import java.net.*;
import java.io.*;

public class SMTPSender {
   
 public static void sendMail(
  String smtpServer, String sender, String recipient, String content)
         throws Exception {
  // will be coded
 }
   
 public static void main(String args[]) {
  try {
   SMTPSender.sendMail(
     "my.smtp.server.addr",
     "sender e-mail",
     "recipient e-mail",
     "내용"
   );
   System.out.println("==========================");
   System.out.println("메일이 전송되었습니다.");
  } catch(Exception e) {
   System.out.println("==========================");
   System.out.println("메일이 발송되지 않았습니다.");
   System.out.println(e.toString());
  }
 }
 
}
 


구조는 간단하다. static 메소드로 sendMail 이라는 메소드가 있다. 이 메소드는 smtpServer, sender, recipient, content 를 받는다. 이

곳에 적당한 값들을 넣어주면, sendMail 이라는 메소드는 실제로 메일을 발송하는 것이다. 따라서 어디서든 메일을 발송하고 싶다면,

SMTPSender.sendMail("서버", "보내는이", "받는이", "내용"); 과 같이 호출해주면 되는 것이다.

그러나 하나 주의할 점이 있다. sendMail() 메소드를 보면 뒤쪽에 throws Exception 이라는 부분이 있다. 이것은 메소드 내부에서 일어나

는 Exception 을 자신(sendMail메소드)을 호출한 곳으로 그대로 전달하라는 의미이다. 즉, 만일 sendMail()메소드내에서 SMTP Server에 소

켓 연결을 시도하는데, SMTP Server주소가 잘못되어있다면, Exception이 발생할 것이다. 이것을 sendMail()메소드 내에서 처리하지 않고

그대로 자신을 호출한 곳에 넘겨주는 것이다. 이렇게 함으로써, 문제가 발생했을때에 sendMail() 메소드를 호출한 곳에서 문제가 발생했고

어떠한 문제인지를 바로 알아낼 수 있는 것이다.

따라서, sendMail()메소드를 호출하기 위해서는, sendMail()이 전달하는 Exception을 받을 준비를 해주어야 하는 것이고, try - catch 문

안에 sendMail() 호출하는 부분을 넣어주어야 하는 것이다. 만일 별다른 Exception이 발생하지 않고, sendMail()메소드 호출이 종료되었다

면 메일은 성공적으로 발송된 것이다. 그러나, 만일 Exception이 발생하여 catch 구문으로 넘어갔다면, 메일은 발송되지 않은것이고 그 이

유는 넘어오는 Exception을 보면 알 수가 있는 것이다. 설명이 너무 장황하지만, main메소드를 보면 간단히 이해할 것이다.

그럼 이제부터, sendMail() 메소드의 내부를 작성해가도록 하자.

 


4. Java 로 구현하기2 - 메소드 구현

sendMail()메소드의 내부 구조는 간단하다. telnet을 이용해 하는 것과 같은 순서를 밟으면 될 것이다. 앞에서 telnet 으로 연결했던 예제

를 보면서 절차를 정리해보자.

Socket 을 생성하여 SMTP서버의 25번 포트에 연결 -> 응답코드 확인(220)
HELO <도메인> 명령을 전송 -> 응답코드 확인(250)
MAIL FROM: <보내는사람> 명령 전송 -> 응답코드 확인(250)
RCPT TO: <받는사람> 명령으로 받는 사람 지정 -> 응답코드 확인(250)
DATA 명령으로 본문입력을 하겠다는 의사전달 -> 응답코드 확인(354)
본문입력
. 를 입력하여 본문입력종료를 알림 -> 응답코드 확인(220)
quit 명령으로 종료
220,250,354 등의 응답코드는 아까 telnet 으로 연결했던 예제를 보고 알아내었다. 그런 숫자가 나오면 OK사인으로 생각할 수 있는 것이다

. 물론 실제로 각 응답코드는 나름대로의 의미가 있고 그것은 이후에 표로 정리하겠다고 했었다. 그것은 RFC821문서에 정리되어있는데,

http://www.ietf.org/rfc/rfc0821.txt에 가면 그 내용을 볼 수 있다. 그러나 이 프로그램에서는 220, 250, 354 등의 코드가 아니면 모두

에러로 간주하도록 하자.

 

 

 

 

5. Socket생성하여 SMTP서버에 연결

SMTP서버의 25번 포트에 연결하는 것은 아주 간단하다. 그냥 new Socket("SMTP서버주소", 25) 와 같이 생성해주면 연결되는 것이다. 또한,

서버에 연결을 했으면 명령을 보내고 응답코드를 받기 위해서는 연결된 Socket에서 Reader와 Writer를 얻어야 할 것이다. 그리고서 마지막

으로, 응답코드가 220인지를 확인해야 할 것이다. 절차를 정리하면 다음과 같을 것이다.

Socket을 생성하여 서버에 연결
응답코드(220) 확인
Socket.getInputStream()에서 Reader 생성
Socket.getOutputStream()에서 Writer 생성
여기서 InputStream을 그냥 쓰지 않고 Reader를 생성하여 사용하는 이유는, Java Stream Overview 를 참조하기 바란다. 간단히 요약하자면

, Binary데이터가 전송된다는 것이 명백하지 않으면 대부분의 경우에는 InputStream/OutputStream 이 아니라 Reader/Writer를 쓰는것이 바

람직하다. 이곳에서는 특히, 한 라인씩 읽거나 전송이 편리한, BufferedReader와 PrintWriter를 사용하도록 하자. 위의 절차대로 코드를

작성하면 다음과 같을 것이다.
   //SMTP서버에 소켓 연결
  Socket socket=new Socket(smtpServer, 25);
  
  // Reader와 Writer를 얻는다.
  BufferedReader br=new BufferedReader(new InputStreamReader( socket.getInputStream() ) );
  PrintWriter pw=new PrintWriter( socket.getOutputStream(), true );
  System.out.println("서버에 연결되었습니다.");
  
  // 응답코드 확인
  String line=br.readLine();
  System.out.println("응답:"+line);
  if (!line.startsWith("220")) {
       // 적당한 에러처리를 해주어야 한다.
  }
 


하나하나 설명을 해보자. 첫 라인에서 Socket()을 생성하여 socket이라는 변수에 넣었다. 이것이 잘 실행되었다면 서버와 연결이 된 것이

다. 다음엔 이곳에서 BufferedReader와 PrintWriter를 얻었다. PrintWriter를 생성할때, true를 반드시 적어주어야 한다. 이것을 적어주지

않으면, printWriter.println()명령을 사용하여도 버퍼에만 데이터를 넣고 실제로 서버에는 데이터를 전송하지 않는 경우가 생기기 때문이

다. 마지막으로, 서버로부터 한 라인을 입력받아서 startsWith 명령어로 첫글자가 220이 맞는지를 확인했다.

try - catch 는 어디갔는가? 당연히 new Socket()이나 br.readLine()같은 메소드는 IOException을 발생하기 때문에, try - catch 문으로

감싸서 IOException을 처리해주어야 하는데, 지금 보면 그런 처리는 해주지 않았다. 그 이유는, sendMail()메소드의 선언부분에 있다. 지

금작성하는 코드는 sendMail()메소드의 내부에 삽입될 것인데, sendMail()메소드는 선언될때 throws Exception 이라고 선언이 된 것이다.

이것은 메소드 내부에서 발생하는 Exception은 모두 자신을 호출한 부분으로 넘기라는 의미이다. 그렇기 때문에, sendMail()메소드를 호출

하는 부분에서 try - catch 를 사용한 것이다.

이제야 비로소, sendMail()메소드를 throws Exception으로 선언한 이유가 해명이 된다. 이렇게 선언하면, 단지 메소드 내부에서 try -

catch 를 사용하지 않아도 된다는 코딩의 편리함 뿐만 아니라, 더욱 중요한 이점을 얻을 수 있다. 그것은 마음대로 Exception을 만들어 전

달할 수 있는 것이다. 위의 코드에서 응답코드가 220이 아니면 에러처리를 해주어야 하는데, 그 부분이 비어있다. 그 부분에서 어떤 일을

해주어야 할까? 보통은 적당히 에러메시지를 출력해주고, return을 사용해서 메소드를 종료시킬 것이다. 그러나 그렇게되면, 메일전송이

잘되었는지, 잘 안되었다면 무슨 이유로 그런건지를 알 수 없을 것이다. 하지만, 여기서 적당한 Exception을 만들어서 전달한다면 어떻게

될까? 그러면, sendMail()메소드를 호출한 곳에서 catch 문에 걸릴 것이고, 그곳에서 적당히 처리를 해주면 될 것이다.

이렇게 Exception의 처리를 떠넘기는 것은 많은 이점이 있다.(물론 단점도 있지만...) 일단 가장 큰 잇점은 클래스의 독립성을 유지하여

재사용성을 높이는 것이다. sendMail()이라는 메소드가 그냥 이 프로그램에서만 쓰고말것이라면, 메소드 내부에서 모든 예외처리를 해주면

된다. 그러나 sendMail()메소드를 사용해서, 여러 프로그램에서 메일을 보낼 것이라면 얘기가 달라진다. 각 프로그램마다 예외처리 방식이

다르기 때문이다. 어떤 프로그램은 그냥 System.out.println()문으로 콘솔에 출력한 다음 프로그램을 종료할 수도 있고, 어떤 프로그램은

스윙이나 awt로 작성되어 대화상자를 띄워서 메시지를 출력할 수도 있다. 이렇게 예외처리 방식이 다르기 때문에, sendMail()메소드에서

함부로 에러를 처리하면 안되는 것이다. 다시 말해 sendMail()메소드가 Exception을 스스로 처리하지 않고 떠넘김(throws)으로써,

sendMail()메소드는 어떤 프로그램에서도 사용할 수 있게 된 것이다.

아무튼, 응답코드가 220이 아니었을 경우엔 새로운 Exception을 하나 생성해서 넘겨(throw)버리면 될 것이다. 그럼 완성된 코드를 한 번

보자.

// SMTPServer.java
import java.net.*;
import java.io.*;

public class SMTPSender {
   
 public static void sendMail(
  String smtpServer, String sender, String recipient, String content)
      throws Exception {
 
  //SMTP서버에 소켓 연결
  Socket socket=new Socket(smtpServer, 25);
  
  // Reader와 Writer를 얻는다.
  BufferedReader br=new BufferedReader(new InputStreamReader( socket.getInputStream() ) );
  PrintWriter pw=new PrintWriter( socket.getOutputStream(), true );
  System.out.println("서버에 연결되었습니다.");
  
  // 응답코드 확인
  String line=br.readLine();
  System.out.println("응답:"+line);
  if (!line.startsWith("220")) {
       throw new Exception("SMTP서버가 아닙니다");
  }


  // will be coded
  
  pw.close();
  br.close();
  socket.close();
 }
   
 public static void main(String args[]) {
  try {
   SMTPSender.sendMail(
      "my.smtp.server.addr",
      "sender e-mail",
      "recipient e-mail",
      "내용"
   );
   System.out.println("==========================");
   System.out.println("메일이 전송되었습니다.");
  } catch(Exception e) {
   System.out.println("==========================");
   System.out.println("메일이 발송되지 않았습니다.");
   System.out.println(e.toString());
  }
 }
 
}
 

컴파일해서 실행을 해보자. 실행이 될 수도 있고, smtpserver의 주소가 잘못되었다면 Exception이 날 것이다. 다시 한 번 말하지만, 코드

중에 my.smtp.server.addr 은 그대로 쓰는 것이 아니라, 자신의 SMTP Server 주소를 넣어주어야 하는 것이다.

다음엔 HELO 명령어를 전송하고, 응답코드(250)를 받아 확인해주면 될 것이다.

 


6. HELO 명령어 전송

사실 이제부터 구현에 대해서 더 설명할 부분은 없다. 4-1에서 모두 설명했기 때문이다. 이 부분 코드를 보고서 부연설명을 하도록 하자.

이 코드는 // will be coded 부분에 들어가면 된다.
 System.out.println("HELO 명령을 전송합니다.");
pw.println("HELO mydomain.name");line=br.readLine();
System.out.println("응답:"+line);
if (!line.startsWith("250")) throw new Exception("HELO 실패했습니다:"+line);
 


pw.println()을 사용해서 HELO 명령을 전송하였다. HELO 다음에 mydomain.name 이라는 부분에 자신의 컴퓨터의 도메인명을 적어주어야 한

다. 하지만, 대부분의 SMTP서버에서 이 부분은 신경쓰지 않고 거의 무시하기때문에, 그냥 그대로 쳐주어도 무방하다.

다음은 한 라인을 br.readLine()으로 전송받아서, 앞부분이 250 인지 확인하였다. 만일 250 이 아니라면 Exception을 생성하여 전달한 것

이다.

 

 

7. MAIL FROM, RCPT TO 명령어 전송

 System.out.println("MAIL FROM 명령을 전송합니다.");
pw.println("MAIL FROM:"+sender);
line=br.readLine();
System.out.println("응답:"+line);
if (!line.startsWith("250")) throw new Exception("MAIL FROM 에서 실패했습니다:"+line);

System.out.println("RCPT 명령을 전송합니다.");
pw.println("RCPT TO:"+recipient);
line=br.readLine();
System.out.println("응답:"+line);
if (!line.startsWith("250")) throw new Exception("RCPT TO 에서 실패했습니다:"+line);
 


마찬가지이다. "MAIL FROM" 명령어와 "RCPT TO" 명령어를 전송하고, 각각 응답코드를 확인하였다.

 

 

8. DATA 명령어와 내용 전송

그래도 DATA명령어를 전송할때는 약간 다르다. 순서가 "DATA명령전송 -> 에러코드(354) 코드 확인 -> 본문전송 -> . 전송 -> 에러코드

(250) 확인" 이 될 것이다. 그냥 그 순서대로 코드를 작성하면 될 것이다.
 System.out.println("DATA 명령을 전송합니다.");
pw.println("DATA");
line=br.readLine();
System.out.println("응답:"+line);
if (!line.startsWith("354")) throw new Exception("DATA 에서 실패했습니다:"+line);

System.out.println("본문을 전송합니다.");
pw.println(content);
pw.println(".");
line=br.readLine();
System.out.println("응답:"+line);
if (!line.startsWith("250")) throw new Exception("내용전송에서 실패했습니다:"+line);
 

 

 

9. QUIT 명령어

이부분은 뭐 생략해도 상관은 없다. 그냥 소켓을 닫아주면(socket.close()) 상대편에서도 같이 닫기 때문이다. 대부분의 서버들은 그렇게

작동을하지만, 그래도 뭐 기분이 있으니까 quit명령어를 보내는 것까지만 하자.
 System.out.println("접속 종료합니다.");
pw.println("quit");
 

 

 

 

 


10. 전체 코드
 // SMTPServer.java
import java.net.*;
import java.io.*;

public class SMTPSender {
   
 public static void sendMail(String smtpServer, String sender, String recipient, String content)
       throws Exception {
  Socket socket=new Socket(smtpServer, 25);
  BufferedReader br=new BufferedReader(new InputStreamReader( socket.getInputStream() ) );
  PrintWriter pw=new PrintWriter( socket.getOutputStream(), true );
  System.out.println("서버에 연결되었습니다.");
  
  String line=br.readLine();
  System.out.println("응답:"+line);
  if (!line.startsWith("220")) throw new Exception("SMTP서버가 아닙니다:"+line);
  
  System.out.println("HELO 명령을 전송합니다.");
  pw.println("HELO mydomain.name");
  line=br.readLine();
  System.out.println("응답:"+line);
  if (!line.startsWith("250")) throw new Exception("HELO 실패했습니다:"+line);
  
  System.out.println("MAIL FROM 명령을 전송합니다.");
  pw.println("MAIL FROM:"+sender);
  line=br.readLine();
  System.out.println("응답:"+line);
  if (!line.startsWith("250")) throw new Exception("MAIL FROM 에서 실패했습니다:"+line);
  
  System.out.println("RCPT 명령을 전송합니다.");
  pw.println("RCPT TO:"+recipient);
  line=br.readLine();
  System.out.println("응답:"+line);
  if (!line.startsWith("250")) throw new Exception("RCPT TO 에서 실패했습니다:"+line);
  
  System.out.println("DATA 명령을 전송합니다.");
  pw.println("DATA");
  line=br.readLine();
  System.out.println("응답:"+line);
  if (!line.startsWith("354")) throw new Exception("DATA 에서 실패했습니다:"+line);
  
  System.out.println("본문을 전송합니다.");
  pw.println(content);
  pw.println(".");
  line=br.readLine();
  System.out.println("응답:"+line);
  if (!line.startsWith("250")) throw new Exception("내용전송에서 실패했습니다:"+line);
  
  System.out.println("접속 종료합니다.");
  pw.println("quit");
  
  br.close();
  pw.close();
  socket.close();
 }
   
 public static void main(String args[]) {
  try {
   SMTPSender.sendMail(
     "my.smtp.server.addr",
     "sender e-mail",
     "recipient e-mail",
     "내용"
   );
   System.out.println("==========================");
   System.out.println("메일이 전송되었습니다.");
  } catch(Exception e) {
   System.out.println("==========================");
   System.out.println("메일이 발송되지 않았습니다.");
   System.out.println(e.toString());
  }
 }
 
}
 


여러 번 반복하는 얘기지만, main메소드의 my.smtp.server.addr, sender-email, recipient e-mail 등은 그대로 입력하는 것이 아니라 자신

의 SMTP서버와, 보내는 메일주소, 받는 메일주소 등을 적어야 한다.

한 번 컴파일해서 실행을 해보자. 그리고 받는 메일주소에 제대로 메일이 전달되었는지를 확인해보자.

 


11. 덤: 스윙을 사용하여 메일전송프로그램 만들기

SMTPSender 클래스는 SMTP프로토콜을 직접 구현하여 메일을 전송하는 프로그램이다. 나름대로 클래스의 재사용성 같은 것을 고려해서 만들

었으니, 스윙을 사용하여 GUI로 실제 메일프로그램을 조금 흉내내보도록 하자.


스윙을 배우기 위한 것이 아니니, 소스를 보면서 설명하도록 한다.
 // SMTPClientBySwing.java
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

public class SMTPClientBySwing extends JPanel implements ActionListener {
 
 JTextField smtpServer=new JTextField(30);
 JTextField sender=new JTextField(30);
 JTextField recipient=new JTextField(30);
 JTextArea content=new JTextArea(10,30);
 JButton sendButton=new JButton("Send");
 JButton exitButton=new JButton("Exit");
 
 public SMTPClientBySwing() {
  JPanel inputPanel=new JPanel( new BorderLayout(10,10) );
  JPanel labelPanel=new JPanel( new GridLayout(3,1,5,5) );
  JPanel textFieldPanel=new JPanel( new GridLayout(3,1,5,5) );
  inputPanel.add( labelPanel, BorderLayout.WEST);
  inputPanel.add( textFieldPanel, BorderLayout.CENTER);
  labelPanel.add( new JLabel("SMTP Server") );
  labelPanel.add( new JLabel("Sender") );
  labelPanel.add( new JLabel("Recipent") );
  textFieldPanel.add( smtpServer );
  textFieldPanel.add(sender);
  textFieldPanel.add(recipient);
  
  JPanel buttonPanel=new JPanel();
  buttonPanel.add( sendButton );
  buttonPanel.add( exitButton );
  sendButton.addActionListener(this);
  exitButton.addActionListener(this);

  this.setBorder( new javax.swing.border.EmptyBorder(10,10,10,10));
  this.setLayout(new BorderLayout(10,10));
  this.add( inputPanel, BorderLayout.NORTH );
  this.add( content, BorderLayout.CENTER );
  this.add( buttonPanel, BorderLayout.SOUTH );
 }
 
 public void actionPerformed(ActionEvent e) {
  if (e.getSource()==exitButton) {
   System.exit(0);
  } else if (e.getSource()==sendButton) {
   try {
    SMTPSender.sendMail(
      smtpServer.getText(),
      sender.getText(),
      recipient.getText(),
      content.getText()
    );
    JOptionPane.showMessageDialog(this, "메일을 전송하였습니다.");
   } catch(Exception ex) {
    JOptionPane.showMessageDialog(
      this,
      ex.toString(), "메일전송 실패",
      JOptionPane.ERROR_MESSAGE
    );
   }
  }
 }
 
 public static void main(String args[]) {
  JFrame f=new JFrame("SMTP Client");
  f.getContentPane().add( new SMTPClientBySwing());
  f.addWindowListener(new WindowAdapter() {
   public void windowClosing(WindowEvent e) {
    System.exit(0);
   }
  });
  f.pack();
  f.setVisible(true);
 }
}
 


중요한 부분은 굵은 글씨로 표시된 부분이다. 이 부분은 Send Button이 눌리면, 실행되는 부분이다. SMTPSender.sendMail()을 적당한 파라

미터와 함께 호출한다. try - catch 를 사용하여, 특별한 문제없이 실행되었으면 메일을 전송했다는 대화상자를 띄우고, Exception이 발생

하면 그것을 대화상자에 표시한다.



출처: https://jang8584.tistory.com/52 [개발자의 길]

반응형
Comments