2014년 1월 28일 화요일

Runtime객체

자바에서 외부파일을 실행시키거나, cmd 명령을 위해서 Runtime객체를 사용한다.

확장자가 .exe로 끝나는 외부파일을 실행시킬때에는
try {
      Process process = Runtime.getRuntime().exec("c:/windows/notepad.exe");     
     } catch (IOException e1) {
      System.out.println(e1);
     }
로 실행시키면된다.

하지만 .exe로 끝나는 파일이 아니면 (예:.mov)
try {
Process process = Runtime.getRuntime().exec("cmd /c d:/test/test.mov"); 
} catch (IOException e1) {
System.out.println(e1);
}
로 실행시켜 줘야한다.
======================================================================
여기에서 process는 cmd창의 Stream을 얻어온다.
cmd창 실행 후 계속 할일이 있다면 process를 이용하면 된다.

2014년 1월 26일 일요일

메일 파일첨부하기

이전에 JavaMail을 이용해서 간단하게 메일을 보내는 방법을 살펴 보았습니다. 이번에는 메일에 파일을 첨부하여 전송하는 방법에 대해서 알아 보겠습니다.
우선 메일에 파일을 첨부하는 것은 웹서버가 존재하는 로컬 파일시스템에 파일을 전송한 다음 전송된 파일을 메일에 첨부해서 MTA(메일서버)에 보내는 방식을 취합니다. 단순히 로컬에서 파일을 보낸다면 그냥 첨부를 시키면 되겠지만, 웹서버가 MUA(메일 클라이언트)의 역할을 해야하므로 이러한 방식을 취한다고 생각하시면 됩니다.
파일 업로드를 어떻게 할 것인가를 결정해야 하는데, 몇몇 파일 업로드 컴포넌트들이 배포되고 있으며 이미 상당기간 동안 검증을 거쳤으므로 직접 제작하는 것보다 이들을 이용하면 좋을 것입니다. 개인적으로는 com.oreilly.servlet 패키지를 사용하는 것을 좋아하며 추천합니다. SmartUpload와 같은 컴포넌트를 사용하셔도 되고, 직접 제작해서 사용하셔도 될 것입니다.
우리는 com.oreilly.servlet 패키지를 이용하도록 합시다. 이 패키지는 http://www.servlets.com 에서 다운로드 하시기 바랍니다. zip파일을 풀면 아래와 같이 폴더리스트가 구성됩니다.
위 화면에서 보시는 바와 같이 cos-19Jun2001/lib폴더에 있는 cos.jar 파일을 역시 클래스 패스가 가능하도록 설정하시면 됩니다.
이제 우리가 JavaMail(1)에서 사용했던 jsp 페이지와 서블릿 클래스를 약간 수정해야 합니다. 먼저 jsp 페이지에서 수정해야 할 부분입니다.
<form method="post" action="/servlet/MailServlet" enctype="multipart/form-data">
form 태그 내부에서 enctype을 multipart/form-data 로 설정하시면 됩니다. 그 다음으로<input type="file" name="file01">을 추가하도록 하시지요.
전체적으로 수정된 JSP 페이지는 아래와 같습니다.
<%@ page contentType="text/html;charset=EUC-KR" %>
<% Boolean success = (Boolean)request.getAttribute("success"); %>
<HTML>
<HEAD>
<TITLE> Mailer </TITLE>
</HEAD>
<BODY>
<center>
<h1> 간단한 메일 전송 </h1>
<form method="post" action="/servlet/MailServlet" enctype="multipart/form-data">
<table>
<tr>
<td>from </td>
<td><input type="text" name="from" value="bnote@naver.com"></td>
</tr>
<tr>
<td>to </td>
<td><input type="text" name="to" value="bluenote@uniboss.com"></td>
</tr>
<tr>
<td>subject </td>
<td><input type="text" name="subject" value="테스트 메일"></td>
</tr>
<tr>
<td> content </td>
<td><textarea name="content" rows=10 cols=30>허떱한 메일 보내기</textarea>
</td>
</tr>
<tr>
<td> file </td>
<td><input type="file" name="file01"></td>
</tr>
<tr><td colspan=2 align=center><input type="submit" value="Transport">
</td>
</tr>
</table>
</form>
<% if(success != null && success.booleanValue() == false){ %>
메일 전송 실패하였습니다.
<% }else if(success != null && success.booleanValue() == true){ %>
정상적으로 전송되었습니다.<%}%>
</BODY>
</HTML>
수정한 화면은 아래와 같지만 여전히 허덥해 보입니다.
이제 servlet 클래스만 수정하시면 됩니다. 앞서 말씀드렸듯이 파일 업로드 후 첨부이므로 업로드를 위한 클래스를 사용해야 합니다. 그리고 첨부에 관련된 클래스는 JavaBeans Activation Framework API에 있습니다. 따라서 두가지 패키지를 더 import 해야 합니다.
import javax.activation.*;
import com.oreilly.servlet.*;
파일 업로드를 위해서, 그리고 multipart/form-data로 넘어오는 파라미터들을 파싱하기 위해서 com.oreilly.servlet.MultipartRequest 클래스를 사용하도록 하겠습니다.
private static final String FILE_PATH = "c:/temp/";
private static final int MAX_SIZE = 5*1024*1024; //5MByte
MultipartRequest request = new MultipartRequest(req, FILE_PATH, MAX_SIZE);
아규먼트로 세 가지(HttpServletRequest, 업로드할 파일의 경로, 업로드할 파일의 최대 크기)를 지정하셔야 합니다. 그래서 두 가지 변수를 더 설정하고 MultipartRequest 객체를 생성하였습니다. 여기서 req는 HttpServletRequest 입니다.
이제 파라미터들은 request에서 얻을 수 있습니다.
String to = request.getParameter("to");
String from = request.getParameter("from");
String subject = request.getParameter("subject");
String content = request.getParameter("content");
"파일 첨부를 하면서 우리의 메시지는 이제 Multipart 가 되었습니다."라고 생각해 주세요. 다중 부분이 생긴 메시지라는 의미로 생각하시면 될 듯 합니다. 이 Multipart의 subClass인 MimeMultipart는 MimeBodyPart를 자식으로 가집니다. 전달하려는 단순메시지 혹은 HTML이 하나의 BodyPart이고, 파일 하나가 또 하나의 BodyPart입니다. 따라서 우리는 두개의 BodyPart를 MultiPart에 넣고 이 MultiPart를 Message의 Content에 담아서 보내면 되는 것입니다.
조금 생소하게 들릴지 모르지만 내용을 음미하면서 다시 한번 읽어보시고 소스 코드를 보시길 권장합니다.
MimeBodyPart mbp01 = new MimeBodyPart();
mbp01.setContent(content, "text/html;charset=EUC-KR");

Multipart mp = new MimeMultipart();
mp.addBodyPart(mbp01);

if(request.getFile("file01") !=null){
MimeBodyPart mbp02 = new MimeBodyPart();
FileDataSource fds = new FileDataSource(request.getFile("file01"));
mbp02.setDataHandler(new DataHandler(fds));
mbp02.setFileName(fds.getName());
fileName = fds.getName(); //임시파일 삭제를 위해 파일이름을 설정

mp.addBodyPart(mbp02);
}

ms.setContent(mp);
위 코드에서 BodyPart의 content를 지정하는 것도 setContent() 메쏘드입니다. 그리고 MultipartRequest의 getFile() 메쏘드가 업로드된 파일을 가져오는 메쏘드입니다. 반환형이 java.io.File이거덩요. 다른 메쏘드에 대해서는 API 문서를 참조하시구요. 이 파일을 javax.activation.FileDataSource의 생성자의 아규먼트로 사용합니다. 아래 부분 처럼 말이죠. file01은 jsp 페이지에서 <file />에서 name 속성에 지정한 것입니다.
FileDataSource fds = new FileDataSource(request.getFile("file01"));
파일 이름은 FileDataSource에서 얻고 BodyPart의 setFileName()으로 파일명을 지정합니다. Multipart에 BodyPart를 추가하고 Message에 Multipart를 추가하면 상황 종료입니다.
Transport.send(ms);
위와 같이 전송하는 부분은 동일합니다. 마지막으로 업로드된 파일을 지워버려야 하므로 메쏘드를 하나 만들어야 할것입니다. 저는 아래와 같이 만들었습니다.
private synchronized void deleteFile(String fileName){
File f = new File(FILE_PATH+fileName);
if(fileName !=null && f.exists())
f.delete();
}
그리고 Transport.send(ms)를 호출한 다음 deleteFile(fileName);을 호출합니다. 전체적인 소스는 아래와 같습니다. 이전에 JavaMail(1)에서 사용한 소스 코드 중 필요없는 부분은 주석으로 처리했습니다.
import javax.servlet.*;
import javax.servlet.http.*;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.util.*;
import javax.activation.*;
import com.oreilly.servlet.*;
public class MailServlet extends HttpServlet{
private static final String SMTP_HOST = "ns.uniboss.com";
private static final String FILE_PATH = "c:/temp/";
private static final int MAX_SIZE = 5*1024*1024; //5MByte
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException{
MultipartRequest request = new MultipartRequest(req, FILE_PATH, MAX_SIZE);
String to = request.getParameter("to");
String from = request.getParameter("from");
String subject = request.getParameter("subject");
String content = request.getParameter("content");
/*
String to = req.getParameter("to");
String from = req.getParameter("from");
String subject = req.getParameter("subject");
String content = req.getParameter("content");
*/
Properties props = new Properties();
props.put("mail.host", SMTP_HOST);
Boolean success = null;
String fileName = null;
try{
Session session= Session.getDefaultInstance(props);
Message ms = new MimeMessage(session);
ms.setFrom(new InternetAddress(from)); ms.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
ms.setSubject(new String(subject.getBytes("8859_1"), "KSC5601"));
//ms.setContent(content, "text/plain");
MimeBodyPart mbp01 = new MimeBodyPart();
mbp01.setContent(content, "text/html;charset=EUC-KR");
Multipart mp = new MimeMultipart();
mp.addBodyPart(mbp01);
if(request.getFile("file01") !=null){
MimeBodyPart mbp02 = new MimeBodyPart();
FileDataSource fds = new
FileDataSource(request.getFile("file01"));
mbp02.setDataHandler(new DataHandler(fds));
mbp02.setFileName(fds.getName());
fileName = fds.getName(); //임시파일 삭제를 위해 파일이름을 설정
mp.addBodyPart(mbp02);
}
ms.setContent(mp);
Transport.send(ms);
success = new Boolean(true);
deleteFile(fileName);
}catch(Exception e){
success = new Boolean(false);
System.out.println(e);
}finally{
req.setAttribute("success", success);
gotoPage("/mail.jsp", req, res);
}
}
public void gotoPage(String address, HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{ RequestDispatcher rd =
getServletContext().getRequestDispatcher(address);
rd.forward(req, res);
}
private synchronized void deleteFile(String fileName){
File f = new File(FILE_PATH+fileName);
if(fileName !=null && f.exists())
f.delete();
}
}
지금까지는 파일 하나만 전송하는 예인데 다중 파일 첨부도 별로 틀린 것은 없습니다.
MultipartRequest에는 public Enumeration getFileNames() 메쏘드가 있는데, Enumeration을 루프돌면서 BodyPart를 생성하고 첨부하면 됩니다.
역시 파일들을 삭제하려면 배열이나 Vector 등 Collection에 담아 놓고 나중에 루프를 돌면서 지우시면 됩니다.
한가지 유의하실 점은 Transport.send()가 호출되기 전에 파일을 지우면 NullPointerException이 발생할 것이며, 전송한 후에는 getFileNames()을 호출하여도 이미 모두 초기화가 되어 버려서 Null을 리턴할 것입니다. 따라서 이 파일목록도 다른 곳에 저장하고 처리하시면 될 듯 합니다.
메일 전송과 관련해서는 JavaMail(1,2)를 통해서 알아 보았습니다. 웹메일 전송에 필요한 큰 줄기를 살펴보았는데 응용해서 여러가지 해보시기 바랍니다.

자바에서 메일을 보내는 것은 생각보다 간단합니다.

자바에서 메일을 보내는 것은 생각보다 간단합니다. 
자바의 확장API인 JavaMail을 사용하면 누구나 쉽게 구현할 수 있습니다. 말하자면, 굳이 HELO, CC, BCC와 같은 SMTP 명령어를 몰라도 가능하다는 것입니다. 하지만, 메일 서버를 개발한다면 SMTP 명령어를 비롯한 관련된 RFC 문서들을 참조하여 직접 개발해야 합니다. Java Mail은 MUA라고 불리우는 메일 클라이언트에 국한된다고 봐도 무방합니다. 몇 개의 클래스는 메일 서버를 개발하는 곳에도 사용할 수 있겠지만 말입니다.
각설하고 JavaMail을 사용하도록 설치해야 할 것입니다.
저는 WindowsXP professional , Tomcat4.0, JDK1.3.1_01에서 테스트 했음을 밝여둡니다.
Tomcat 4.0의 common/lib 디렉토리에 가보면 mail.jar 파일과 activation.jar 파일이 이미 들어 있습니다. 하지만, Doc 문서 등과 다른 참조문서들을 얻기 위해서 Sun으로부터 파일을 다운로드 하도록 하시지요.
우선 JavaMail은 http://java.sun.com/products/javamail/index.html에서 다운로드 하실 수 있습니다. 이 글을 쓰는 시점에서 가장 최신 버전은 1.2 입니다.
그리고, JavaBeans Activation Framework (JAF)가 필요한데 아래의 주소에서 다운로드 하십시오. 역시 이 글을 쓰는 시점의 최신 버전은1.0.1입니다.
http://java.sun.com/products/javabeans/glasgow/jaf.html
두 파일 모두 zip으로 묶여 있으므로 압축을 풀어 봅니다.
압축을 풀면 여러 개의 jar파일과 문서들을 볼 수 있습니다. JavaMail에서는 우선 mail.jar 파일을 JAF에서는 activation.jar 파일을 적절히 클래스 패스를 잡아줍니다.
저같은 경우에는 대부분의 jar 파일은 %JAVA_HOME%(자바 설치 디렉토리)의 jre/lib/ext 폴더에 복사해 넣습니다. JVM이 자동으로 이 곳에 있는 jar 파일들을 클래스 패스로 잡기 때문에 jar 파일들을 여기에 두시면 됩니다.
아래에는 javamail, jaf의 압축을 푼 디렉토리 모습과 jar 파일을 클래스 패스에 추가한 모습을 보여줍니다. Javamail과 jaf는 공통적으로 demo 폴더와 docs 폴더가 있습니다.
Demo 폴더에는 많은 예제 소스 코드가 있으니 공부하시는데 충분한 도움이 되실 겁니다. 그리고 docs 폴더에서 스펙 PDF 문서와 JavaDoc 문서가 있으니 API를 참조하시도록 하세요.
그림으로 보는 것이 이해가 빠를 듯 하여 화면을 캡처하였습니다.
[ JavaMail ]
[ JavaBeans Activation Framework ]
[클래스 패스에 추가한 폴더 모습]
일단, 두가지 jar 파일이 클래스 패스에 추가되었다면 이제 코딩할 준비가 되었습니다. 우선 못생긴 JSP 페이지를 하나 만들어 보도록 하지요. 단순히 메일 송신자, 수신자, 제목, 내용을 입력하고 전송하는 것입니다.
파일 전송을 성공했는지 실패했는지는 request 객체의 key 값 success로 판단하기로 합니다. Boolean의 값이 true면 성공, 실패면 false를 반환할 것입니다. 
JSP 페이지의 내용은 아래와 같습니다.
<%@ page contentType="text/html;charset=EUC-KR" %>
<% Boolean success = (Boolean)request.getAttribute("success"); %>
<HTML>
<HEAD>
<TITLE> Mailer </TITLE>
</HEAD>
<BODY>
<center><h1> 간단한 메일 전송 </h1>
<form method="post" action="/servlet/MailServlet">
<table>
<tr>
<td>from </td>
<td><input type="text" name="from"></td>
</tr>
<tr>
<td>to</td>
<td><input type="text" name="to"></td>
</tr>
<tr>
<td>subject </td>
<td><input type="text" name="subject"></td>
</tr>
<tr>
<td>content </td>
<td><textarea name="content" rows=10 cols=30>허떱한 메일 보내기</textarea>
</td>
</tr>
<tr>
<td colspan=2 align=center><input type="submit" value="Transport">
</td>
</tr>
</table>
</form>
<% if(success != null && success.booleanValue() == false){ %>
메일 전송 실패하였습니다.
<% }else if(success != null && success.booleanValue() == true){ %>
정상적으로 전송되었습니다.<%}%>
</BODY>
</HTML>
얼마나 못생긴 화면인지 아래와 그림을 보시기 바랍니다.
이제 이 JSP 페이지의 action이 될 서블릿을 만들어 봅시다. 물론 이 서블릿 클래스는 JSP 페이지로 만들어도 됩니다. 테스트용이니 여러분의 마음이 끌리는 대로 하시기 바랍니다. 저는 요청 처리는 무조건 서블릿으로 하는 버릇(?)이 있어서 서블릿으로 작성하였습니다. 소스 코드는 아래와 같습니다.
우선 몇가지 설명을 하겠습니다.
자바 메일에서 Session이라는 객체가 있는데, 이는 자신의 static 메쏘드인 getDefaultInstance() 혹은 getInstance()로 얻을 수 있습니다. Session 객체는 메일 서버와 프로그램간의 하나의 통신객체라고 이해하면 좋을 듯합니다.
위 두가지 메쏘드들은 java.util.Properteis 객체를 아규먼트로 받습니다. 따라서 먼저 Properties 객체를 생성하고 이 객체에 mail.host 혹은 mail.smtp.host라는 키로 메일 서버의 도메인 주소를 설정하도록 합니다. 이외에도 여러가지 설정을 할 수 있는데, 다음에 시간이 나면 정리하도록 하겠습니다.
실제적으로 메일 메시지는 Message 객체로 보내집니다. Message의 여러 메쏘드들로 값들을 설정합니다.
우선 setFrom() 으로 보내는 사람의 메일주소를 설정합니다. 아규먼트로는 InternetAddress 객체를 받게 되는데, InternetAddress 객체는 메일 주소로 생성됩니다.
setRecipient() 메쏘드는 받을 사람을 지정하게 되는데,
Message.RecipientType.TO
Message.RecipientType.CC
Message.RecipientType.BCC
중 하나를 설정하게 됩니다. SMTP 명령어를 아시는 분들은 쉽게 이해하시겠지만, CC는 참조, BCC는 숨은 참조입니다. 우선 우리는 TO에만 값을 설정하기로 하지요.
setSubject()에서 제목을 String으로 지정하게 되구요. 소스에서는 한글 처리 때문에 한글 변환을 하였습니다.
setContent()에서 이제 메일의 내용을 쓰게되는데, 두번째 아규먼트에서 type을 지정하게 됩니다. 여기서는 단순 text로 가정하고 text/plain으로 설정하였습니다. 우리가 JSP에서 page 지시자에서 contentType을 지정하는 것과 같다고 생각하시면 됩니다. 따라서 charset을 지정하실 수도 있습니다.
마지막으로 전송하는 일만 남았는데, Transport클래스의 send()를 사용하시면 됩니다.
지금까지 일련의 처리는MessagingException을 처리해야하므로, try - catch를 사용하였습니다. 간단한 text 메일 보내기의 서블릿 소스는 아래와 같습니다.
import javax.servlet.*;
import javax.servlet.http.*;
import javax.mail.*;
import javax.mail.internet.*;
import java.io.*;
import java.util.*;
public class MailServlet extends HttpServlet{
private static final String SMTP_HOST = "localhost";
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{
String to = req.getParameter("to");
String from = req.getParameter("from");
String subject = req.getParameter("subject");
String content = req.getParameter("content");
Properties props = new Properties();
props.put("mail.host", SMTP_HOST);
Boolean success = null;
try{
Session session= Session.getDefaultInstance(props);
Message ms = new MimeMessage(session);
ms.setFrom(new InternetAddress(from)); ms.setRecipient(Message.RecipientType.TO, new InternetAddress(to)); ms.setSubject(new String(subject.getBytes("8859_1"), "KSC5601")); ms.setContent(content, "text/plain");
Transport.send(ms);
success = new Boolean(true);
}catch(Exception e){
success = new Boolean(false);
System.out.println(e);
}finally{
req.setAttribute("success", success);
gotoPage("/mail.jsp", req, res);
}
}
public void gotoPage(String address, HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException{ RequestDispatcher rd = getServletContext().getRequestDispatcher(address); rd.forward(req, res);
}
}
간단한 메일을 보내는 메일보내기는 여기서 마무리 짓도록 하겠습니다. JavaMail로 이메일을 보내는 것이 얼마나 간단한 것인지를 아시게 되었을 것입니다.

2014년 1월 24일 금요일

JSP/서블릿으로 Gmail을 이용하여 메일 보내기

사용자가 적은 내용을 내 메일계정으로 보내도록 만들려고 여기저기 찾아본 끝에 결국 완료했다.
필요한 라이브러리는 Javabeans Activation Framework (JAF)와 JavaMail 이 두가지이다.
두 라이브러리를 다운 받아 적당한 폴더에 넣는다. 내 경우에는 이클립스에서 프로젝트폴더/WebContent/WEB-INF/lib 에 압축을 푼 JAR 파일들을 복사해넣었다.
두 라이브러리를 설치했다면 코드를 작성한다. 내가 작성한 코드는 JSP에서 form을 이용해 이름, 이메일주소, 제목, 내용을 입력받고 이 내용을 서블릿으로 보내고 서블릿에서 파라미터로 받은 내용을 메일로 보낸 다음, 처리 결과에 따라 적절한 결과 페이지로 보내게 되어있는 구조이다.
JSP의 form 입력양식 페이지는 어려울게 없다. 문제는 서블릿 부분이었다.
인터넷을 찾아보니 소스가 많이 있긴한데 대부분은 로컬 메일서버를 이용하는 방법들이었고 내 서버 역시 SendMail이 있긴하지만 굳이 그걸 쓸 필요도 없고 지메일쪽의 SMTP를 쓰는게 더 나을 것 같아서 방법을 찾아보았다. 지메일쪽은 SSL을 이용한 인증을 하고 있어서 이것저것 옵션을 붙여야할 것들이 많았다.
SendMail.java 서블릿의 코드는 다음과 같다.
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package mailer;
 
import java.io.IOException;
import java.util.Properties;
 
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * Servlet implementation class SendMail
 */
public class SendMail extends HttpServlet {
    private static final long serialVersionUID = 1L;
 
    /**
     * @see HttpServlet#HttpServlet()
     */
    public SendMail() {
        super();
        // TODO Auto-generated constructor stub
    }
 
    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
    }
 
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
 
        request.setCharacterEncoding("UTF-8");
 
        response.setContentType("text/html;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
 
        String m_name =     request.getParameter("name");
        String m_email =    request.getParameter("email");
        String m_title =    request.getParameter("title");
        String m_text =     request.getParameter("text");
 
        try {
            String mail_from =  m_name + "<" + m_email + ">";
            String mail_to =    "admin<admin@83rpm.com>";
            String title =      "hosting.83rpm.com 요청사항 :: " + m_title;
            String contents =   "보낸 사람 :: " + m_name + "&lt;" + m_email + "&gt;<br><br>" + m_title + "<br><br>" + m_text;
 
            mail_from = new String(mail_from.getBytes("UTF-8"), "UTF-8");
            mail_to = new String(mail_to.getBytes("UTF-8"), "UTF-8");
 
            Properties props = new Properties();
            props.put("mail.transport.protocol", "smtp");
            props.put("mail.smtp.host", "smtp.gmail.com");
            props.put("mail.smtp.port", "465");
            props.put("mail.smtp.starttls.enable", "true");
            props.put("mail.smtp.socketFactory.port", "465");
            props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
            props.put("mail.smtp.socketFactory.fallback", "false");
            props.put("mail.smtp.auth", "true");
 
            Authenticator auth = new SMTPAuthenticator();
 
            Session sess = Session.getDefaultInstance(props, auth);
 
            MimeMessage msg = new MimeMessage(sess);
 
            msg.setFrom(new InternetAddress(mail_from));
            msg.setRecipient(Message.RecipientType.TO, new InternetAddress(mail_to));
            msg.setSubject(title, "UTF-8");
            msg.setContent(contents, "text/html; charset=UTF-8");
            msg.setHeader("Content-type", "text/html; charset=UTF-8");
 
            Transport.send(msg);
 
            response.sendRedirect("request_complete.jsp");
        } catch (Exception e) {
            response.sendRedirect("request_failed.jsp");
        } finally {
 
        }
    }
 
}
중요한건 인증에 대한 부분인데 Session 객체에 이 인증에 대한 객체를 넣어줘야한다. 이 인증 객체는 내가 참조한 다른 글이나 구글링을 해서 찾은 외국문서들에도 모두다 하나의 클래스로 구현하고 있었다. 굳이 왜 그래야하는지는 잘 모르겠지만 어쨌튼 나도 따로 클래스 하나로 구현했다.
SMTPAuthenticator.java의 코드이다.
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
 *
 */
package mailer;
 
import javax.mail.PasswordAuthentication;
import javax.mail.Authenticator;
 
/**
 * @author viper9
 *
 */
public class SMTPAuthenticator extends Authenticator {
    public SMTPAuthenticator() {
        super();
    }
 
    public PasswordAuthentication getPasswordAuthentication() {
        String username = "지메일주소";
        String password = "지메일암호";
        return new PasswordAuthentication(username, password);
    }
}
Authenticator를 상속받는 이러한 인증객체를 따로 구현한 다음 위 서블릿 클래스와 같은 디렉토리에 넣는다.
이 서블릿 클래스에 파라미터로 name, email, title, text 파라미터를 주면 설정된 메일 주소로 메일을 보내게 된다. 받는 사람도 따로 받고 싶다면 역시 파라미터로 받으면 그만이다.
난 서버의 거의 모든 부분에서 UTF-8 인코딩만 쓰고 있고 MySQL도 UTF-8을 기준으로 구성되어있으며 자바 작업을 할 때도 UTF-8을 선호하는 편이라 입력되는 파라미터들을 모두 UTF-8로 처리해주며 작업했다.
작업하며 어려웠던건 인증객체를 생성할 때 사용하는 SMTPAuthenticator 클래스를 만들 때였는데 이게 이클립스의 자동완성을 믿고 하다가 스펠링이 몇개 틀려서 한참 애먹었다. 내가 참조하던 그 문서도 아마 이 스펠링이 틀렸던 것으로 기억한다.Authentication와 Authenticator 이 스펠링이 틀리면 자바가 계속 암호가 틀린거 아니냐고 에러를 출력한다. 굉장히 짜증나던 부분.
여튼 한참 디버깅 끝에 오류를 잡고 나서 작동해보니 메일은 잘 오는데 몇가지 문제점이 있었다.
  1. 메일을 보내는 속도가 빠르지 않다. 외국서버라 그런지 메일을 보내고 나서 2~3초 후에 결과가 수신되는 것 같다. form의 submit 버튼을 사용자가 연속으로 누를 가능성이 있어서 이 부분을 조치를 취해야할 것 같다.
  2. 메일이 바로바로 오지 않는다. 바로바로 올때도 있는데 안 그럴 때도 꽤 많다. 메일을 보내고 나서 몇초 후에 도착하는 일이 꽤 많았다.
  3. 이걸 이용해서 메일을 받아보면 보낸 사람이 SMTPAuthenticator 클래스에서 설정한 그 지메일주소로 설정된다. 내가 따로 지정해주고 싶은데 아무리 해도 되질 않았다. Properties에서 설정이 가능할 것 같기도한데 찾지 못했다. (혹시 아시는 분은 답글 좀 부탁드립니다.)
위 3번 문제 때문에 이걸 이용해서 메일을 보내면 보낸 사람 정보를 알수 없어서 아예 메일 본문에다가 보낸 사람의 이름과 메일주소까지 넣도록 서블릿 클래스에 추가해야했다.
메일러의 메일주소를 따로 부여하기 위해 noreply@83rpm.com으로 메일 주소를 하나 만들어줬다. (지메일은 만들고 한번 로그인해야 비로고 SMTP 서버를 사용가능하다.)
이로써 사용자요청사항을 받는 페이지는 적절히 구현되었다. 이걸 정리해서 아예 메일 송신 전용 클래스로 만들어놔야겠다.