반응형

출처:

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 예외가 발생하였다.

한참을 찾아본 결과 오타가 원인이었다.


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들을 받기 위해서는 다음과 같은 코드를 사용해야 했다.


		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으로 이 파일의 사본을 만들어 그걸 보내는 방법이었다.

			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

보내는 사람과 받는 사람 등의 값을 받는 페이지이다.

<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의 메소드에 대입하여

나온 결과에 따른 뒷처리를 하는 페이지이다.

<%@ 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

실질적으로 메일을 보내기 위한 작업들을 하는 자바빈즈 파일이다.

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