반응형

출처:

http://www.berrycracker.net/archives/2133

http://stackoverflow.com/questions/2422468/how-to-upload-files-to-server-using-jsp-servlet/2424824#2424824

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을 한 번 열어보니 엑세스 문제도 나와 있었다.

일단 본인이기 때문에 보안 수준이 낮은 앱의 엑세스를 허용하였다.


그런데 파일을 보낼려고 하니 파일의 경로를 찾을 수 없다고 나왔다.

찾아보니 htmlform 태그 인코딩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);
    }
}


확실히 최신 정보를 받기 위해서는 구글이 최고라는 사실을 이번에도 또 느낄 수 있었다.


반응형
Posted by 애콜라이트
l

free counters