출처:
http://www.berrycracker.net/archives/2133
http://www.mkyong.com/java/how-to-convert-inputstream-to-file-in-java/
JSP 예제에서 Javamail과 gmail 서버를 이용해 메일을 보내는 예제를 공부하고 있었다.
다 쳐서 이제 실행하려는 순간 ClassNotFoundException 예외가 발생하였다.
한참을 찾아본 결과 오타가 원인이었다.
1 2 3 4 | Properties props = new Properties(); /* 중략 */ // props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory()"); props.put( "mail.smtp.socketFactory.class" , "javax.net.ssl.SSLSocketFactory" ); |
저 주석처럼 괄호가 뒤에 붙어서 클래스를 찾을 수 없었다.
그래서 그 괄호를 떼어 다른 결과를 얻을 수 있었다.
보통 이런 뻘짓 하나 찾아내면 다음엔 잘 되었는데 한참을 기다려도 뭐가 되는 게 없었다.
그래서 gmail 포트를 변경하였다.
예제에는 465 포트를 사용하라고 되어 있었지만,
587 포트로 변경하니 일단 접속은 되었다.
그래도 안 되는 거 같아 gmail을 한 번 열어보니 엑세스 문제도 나와 있었다.
일단 본인이기 때문에 보안 수준이 낮은 앱의 엑세스를 허용하였다.
그런데 파일을 보낼려고 하니 파일의 경로를 찾을 수 없다고 나왔다.
찾아보니 html의 form 태그 인코딩을 multipart/form-data로 바꾸라고 해서 바꿨더니,
이제는 input으로 넘겨준 값들이 안 넘어 가버리는 상황까지 이르렀다.
혹시나 해서 request.getParameter()로 확인해보니 애초에 넘어오는 것이 없었다.
여기서 또 다시 한참을 찾아보니 서블릿 3.0부터 지원하기 시작한 multipart/form-data에서
request.getParameter()는 NULL을 리턴해버린다고 한다.
그래서 내가 넘겨준 form 태그 안의 name들을 받기 위해서는 다음과 같은 코드를 사용해야 했다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | List<fileitem> items; InputStream fileContent = null ; try { items = new ServletFileUpload( new DiskFileItemFactory()).parseRequest(request); for (FileItem item : items) { if (item.isFormField()) { // input 타입의 값이 file이 아닌 경우 if (item.getFieldName().equals( "sender" )) sender = item.getString(); if (item.getFieldName().equals( "receiver" )) receiver = item.getString(); if (item.getFieldName().equals( "cc" )) cc = item.getString(); if (item.getFieldName().equals( "subject" )) subject = item.getString(); if (item.getFieldName().equals( "contents" )) contents = item.getString(); } else { // input 타입의 값이 file인 경우 System.out.println( "Filed Name: " + item.getFieldName()); System.out.println( "Filed Value (File Name): " + item.getName()); filename = FilenameUtils.getName(item.getName()); fileContent = item.getInputStream(); } } } catch (FileUploadException fe) { // TODO Auto-generated catch block fe.printStackTrace(); } catch (IOException ie) { // TODO: handle exception ie.printStackTrace(); } |
저렇게 해서 값을 넘겨주는데는 성공했으나 여전히 파일 위치를 찾을 수 없다고 나왔다.
이에 대해서도 찾아본 결과 아까 위에서 생성하여 파일 내용을 저장한 InputStream을 이용하여
OutputStream으로 이 파일의 사본을 만들어 그걸 보내는 방법이었다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | if (!filename.equals( "" )) { File file = new File(filename); OutputStream fileWriter = new FileOutputStream(file); int read = 0 ; byte [] bytes = new byte [ 1024 ]; while ((read = fileContent.read(bytes)) != - 1 ) { fileWriter.write(bytes, 0 , read); } fileWriter.close(); MimeBodyPart attach = new MimeBodyPart(); // attach.setDataHandler(new DataHandler(file)); // attach the file setting as the file name // attach.setFileName(MimeUtility.encodeWord(file.getName())); attach.attachFile(file); mp.addBodyPart(attach); } |
그래서 여기까지 하고 시도해보니 원하는대로 결과가 나왔다.
다음은 해당 내용들을 추가하여 만든 Javamail 예제이다.
1. FormMail.html
보내는 사람과 받는 사람 등의 값을 받는 페이지이다.
1 2 3 4 5 6 7 8 9 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 | < html > < head > < meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8" > < title >JSP Form Mail</ title > < style type = "text/css" > body { font-size: 9pt; } </ style > </ head > < body > < h2 >Java Mail Test</ h2 > < form name = "fmail" method = "post" action = "SendMail.jsp" enctype = "multipart/form-data" > < table border = "1" cellpadding = "5" > < tr > < td >Sender's E-mail</ td > < td >< input type = "text" name = "sender" size = "50" ></ td > </ tr > < tr > < td >Receiver's E-mail</ td > < td >< input type = "text" name = "receiver" size = "50" ></ td > </ tr > < tr > < td >Carbon Copy's E-mail</ td > < td >< input type = "text" name = "cc" size = "50" ></ td > </ tr > < tr > < td >Mail Title</ td > < td >< input type = "text" name = "subject" size = "50" ></ td > </ tr > < tr > < td >Attachment File</ td > < td >< input type = "file" name = "filename" size = "50" ></ td > </ tr > < tr > < td >Mail Context</ td > < td > < textarea name = "contents" rows = "10" cols = "40" ></ textarea > </ td > </ tr > < tr > < td colspan = "2" align = "center" > < input type = "submit" value = "Send Mail" > </ td > </ tr > </ table > </ form > </ body > </ html > |
2. SendMail.jsp
FormMail.html을 통해서 받은 내용을 자바빈으로 가져온 Sendmail.java의 메소드에 대입하여
나온 결과에 따른 뒷처리를 하는 페이지이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> < jsp:useBean id = "smail" scope = "page" class = "myjsp.mail.Sendmail" /> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> < html > < head > < meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8" > < title >JSP Mail Test</ title > </ head > < body > <% request.setCharacterEncoding("UTF-8"); %> <% if (smail.mailSender(request)) { out.println("< center >< h2 >" + "THe mail was sent normally</ h2 >"); if (!smail.getReceiver().equals("")) out.println("Mail Receiver(To): " + smail.getReceiver() + "< br >"); if (!smail.getCc().equals("")) out.println("Carbon Copy(To): " + smail.getCc()); out.println("< hr >< a href = 'JSPFormMail.jsp' >Write the mail</ a ></ center >"); } else { out.println("< script >alert('Exception occured during sending the mail'); history.go(-1);</ script >"); } %> </ body > </ html > |
3. Sendmail.java
실질적으로 메일을 보내기 위한 작업들을 하는 자바빈즈 파일이다.
1 2 3 4 5 6 7 8 9 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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | public class Sendmail { private String sender; private String receiver; private String cc; private String subject; private String contents; private String filename; private String errMsg; public Sendmail() { sender = "" ; receiver = "" ; cc = "" ; subject = "" ; contents = "" ; filename = "" ; errMsg = "" ; } public boolean mailSender(HttpServletRequest request) { List<fileitem> items; InputStream fileContent = null ; try { items = new ServletFileUpload( new DiskFileItemFactory()).parseRequest(request); for (FileItem item : items) { if (item.isFormField()) { System.out.println( "Filed Name: " + item.getFieldName()); System.out.println( "Filed Value: " + item.getString()); if (item.getFieldName().equals( "sender" )) sender = item.getString(); if (item.getFieldName().equals( "receiver" )) receiver = item.getString(); if (item.getFieldName().equals( "cc" )) cc = item.getString(); if (item.getFieldName().equals( "subject" )) subject = item.getString(); if (item.getFieldName().equals( "contents" )) contents = item.getString(); } else { System.out.println( "Filed Name: " + item.getFieldName()); System.out.println( "Filed Value (File Name): " + item.getName()); filename = FilenameUtils.getName(item.getName()); fileContent = item.getInputStream(); } } } catch (FileUploadException fe) { fe.printStackTrace(); } catch (IOException ie) { // TODO: handle exception ie.printStackTrace(); } Properties props = new Properties(); props.put( "mail.transport.protocol" , "smtp" ); props.put( "mail.smtp.auth" , "true" ); props.put( "mail.smtp.host" , "smtp.gmail.com" ); props.put( "mail.smtp.port" , "587" ); props.put( "mail.smtp.socketFactory.port" , "587" ); props.put( "mail.smtp.starttls.enable" , "true" ); props.put( "mail.smtp.socketFactory.fallback" , "false" ); props.put( "mail.smtp.socketFactory.class" , "javax.net.ssl.SSLSocketFactory" ); props.put( "mail.smtp.timeout" , 5000 ); java.security.Security.addProvider( new com.sun.net.ssl.internal.ssl.Provider()); try { // 인증된 SMTP 사용자 정보를 가진 Authenticator 객체를 만든다. Authenticator auth = new SMTPAuthenticator(); // props와 auth를 이용해 Session 인스턴스를 만든다. Session session = Session.getDefaultInstance(props, auth); // session을 이용해 MimeMessage 객체를 만든다. MimeMessage msg = new MimeMessage(session); // 헤더를 설정한다. msg.addHeader( "Content-Transfer-Encoding" , "base64" ); msg.addHeader( "Reply-To" , sender); System.out.println( "Sender: " + sender); // 보내는 날짜를 현재 날짜로 설정한다. msg.setSentDate( new Date()); // 보내는 사람의 InternetAddress 객체를 준비한다. InternetAddress from = new InternetAddress(sender); msg.setFrom(from); // 받는 사람이 여러명일 경우 쉼표(,)로 구분한다. if (!receiver.equals( "" )) { StringTokenizer st = new StringTokenizer(receiver, "," ); while (st.hasMoreTokens()) { InternetAddress to = new InternetAddress(st.nextToken()); msg.addRecipient(Message.RecipientType.TO, to); } } // 참조자가 여러명일 경우 쉼표(,)로 구분한다. if (!cc.equals( "" )) { StringTokenizer stcc = new StringTokenizer(cc, "," ); while (stcc.hasMoreTokens()) { InternetAddress tocc = new InternetAddress(stcc.nextToken()); msg.addRecipient(Message.RecipientType.CC, tocc); } } // UTF-8 캐릭터 셋을 사용하여 메일 제목을 작성한다. msg.setSubject(subject, "utf-8" ); // MimeMultipart 객체와 MimeBodypart 객체를 사용하여 메일 내용을 작성한다. MimeMultipart mp = new MimeMultipart(); MimeBodyPart body = new MimeBodyPart(); body.setContent(contents, "text/html; charset=utf-8" ); mp.addBodyPart(body); // 메일에 첨부파일이 있으면 MimeBodypart 객체를 만든다. // 파일과 MimeBodypart 객체를 MimeMultipart 객체에 추가한다. if (!filename.equals( "" )) { File file = new File(filename); OutputStream fileWriter = new FileOutputStream(file); int read = 0 ; byte [] bytes = new byte [ 1024 ]; while ((read = fileContent.read(bytes)) != - 1 ) { fileWriter.write(bytes, 0 , read); } fileWriter.close(); MimeBodyPart attach = new MimeBodyPart(); attach.attachFile(file); mp.addBodyPart(attach); } msg.setContent(mp, "text/html; charset=utf-8" ); msg.saveChanges(); Transport tp = session.getTransport( "smtp" ); tp.connect(); tp.sendMessage(msg, msg.getAllRecipients()); tp.close(); } catch (MessagingException me) { me.getMessage(); me.printStackTrace(); return false ; } catch (Exception e) { e.getMessage(); e.printStackTrace(); return false ; } return true ; } public String getSender() { return sender; } public String getReceiver() { return receiver; } public String getCc() { return cc; } public String getSubject() { return subject; } public String getContents() { return contents; } public String getFilename() { return filename; } public String getErrMsg() { return errMsg; } } // SMTP 서버에 접속하기 위한 사용자의 ID와 비밀번호를 입력한다. class SMTPAuthenticator extends Authenticator { protected PasswordAuthentication getPasswordAuthentication() { String id = "구글 ID" ; // @ 이하는 제외한다. String pw = "구글 비밀번호" ; return new PasswordAuthentication(id, pw); } } |
확실히 최신 정보를 받기 위해서는 구글이 최고라는 사실을 이번에도 또 느낄 수 있었다.