package servlet;
/*
* Copyright 1998, 1999 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Sun Microsystems nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.*;
import java.util.*;
import java.text.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
/**
* This is a servlet that demonstrates the use of JavaMail APIs in a 3-tier
* application. It allows the user to login to an IMAP store, list all the
* messages in the INBOX folder, view selected messages, compose and send a
* message, and logout.
* <p>
* Please note: This is NOT an example of how to write servlets! This is simply
* to show that JavaMail can be used in a servlet.
* <p>
* For more information on this servlet, see the JavaMailServlet.README.txt
* file.
* <p>
* For more information on servlets, see <a
* href="http://java.sun.com/products/java-server/servlets/index.html">
* http://java.sun.com/products/java-server/servlets/index.html</a>
*
* @author Max Spivak
*/
public class JavaMailServlet extends HttpServlet implements SingleThreadModel {
String protocol = "imap";
String mbox = "INBOX";
/**
* This method handles the "POST" submission from two forms: the login form
* and the message compose form. The login form has the following
* parameters: <code>hostname</code>, <code>username</code>, and
* <code>password</code>. The <code>send</code> parameter denotes that the
* method is processing the compose form submission.
*/
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
//req.setCharacterEncoding("UTF-8");
//res.setCharacterEncoding("UTF-8");
// get the session
HttpSession ssn = req.getSession(true);
String send = req.getParameter("send");
String host = req.getParameter("hostname");
String user = req.getParameter("username");
String passwd = req.getParameter("password");
URLName url = new URLName(protocol, host, -1, mbox, user, passwd);
ServletOutputStream out = res.getOutputStream();
res.setContentType("text/html;charset=UTF-8");
out.println("<html><body bgcolor=\"#CCCCFF\">");
if (send != null) {
System.out.println("... process message sending...");
send(req, res, out, ssn);
} else {
// initial login
// create
MailUserData mud = new MailUserData(url);
// ssn.putValue("javamailservlet", mud);
ssn.setAttribute("javamailservlet", mud);
try {
Properties props = System.getProperties();
props.put("mail.smtp.host", host);
props.put("mail.smtp.port", 25);
props.put("mail.smtp.auth", "true");
props.put("mail.transport.protocol", "smtp");
//props.put("mail.smtp.starttls.enable", "true");
//props.put("mail.smtp.user", "jinny@usemodj.com");
//props.put("mail.smtp.password", "jinny");
//Cannot refer to a non-final variable inside an inner class defined in a different method
final Vector<String> v = new Vector<String>();
v.add(user);
v.add(passwd);
javax.mail.Authenticator authenticator = new javax.mail.Authenticator() {
protected javax.mail.PasswordAuthentication getPasswordAuthentication() {
// return new javax.mail.PasswordAuthentication(
// "usemodj@gmail.com", "qkfkathfl");
return new javax.mail.PasswordAuthentication(
v.get(0), v.get(1));
}
};
Session session = Session.getDefaultInstance(props,
authenticator);
// Session session = Session.getDefaultInstance(props, null);
session.setDebug(true);
Store store = session.getStore(url);
store.connect();
// store.connect("jinny@usemodj.com", "jinny");
Folder folder = store.getDefaultFolder();
if (folder == null)
throw new MessagingException("No default folder");
folder = folder.getFolder(mbox);
if (folder == null)
throw new MessagingException("Invalid folder");
folder.open(Folder.READ_WRITE);
int totalMessages = folder.getMessageCount();
Message[] msgs = folder.getMessages();
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
folder.fetch(msgs, fp);
// track who logged in
System.out.println("Login from: " + store.getURLName());
// save stuff into MUD
mud.setSession(session);
mud.setStore(store);
mud.setFolder(folder);
// splash
out.print("<center>");
out.print("<font face=\"Arial,Helvetica\" font size=+3>");
out.println("<b>Welcome to JavaMail!</b></font></center><p>");
// folder table
out.println("<table width=\"50%\" border=0 align=center>");
// folder name column header
out.print("<tr><td width=\"75%\" bgcolor=\"#ffffcc\">");
out.print("<font face=\"Arial,Helvetica\" font size=-1>");
out.println("<b>FolderName</b></font></td><br>");
// msg count column header
out.print("<td width=\"25%\" bgcolor=\"#ffffcc\">");
out.print("<font face=\"Arial,Helvetica\" font size=-1>");
out.println("<b>Messages</b></font></td><br>");
out.println("</tr>");
// folder name
out.print("<tr><td width=\"75%\" bgcolor=\"#ffffff\">");
out.print("<a href=\"" + HttpUtils.getRequestURL(req) + "\">"
+ "Inbox" + "</a></td><br>");
// msg count
out.println("<td width=\"25%\" bgcolor=\"#ffffff\">"
+ totalMessages + "</td>");
out.println("</tr>");
out.println("</table");
} catch (Exception ex) {
out.println(ex.toString());
} finally {
out.println("</body></html>");
out.close();
}
}
}
/**
* This method handles the GET requests for the client.
*/
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
//res.setCharacterEncoding("UTF-8");
//req.setCharacterEncoding("UTF-8");
HttpSession ses = req.getSession(false); // before we write to out
ServletOutputStream out = res.getOutputStream();
MailUserData mud = getMUD(ses);
if (mud == null) {
res.setContentType("text/html;charset=UTF-8");
out.println("<html><body>Please Login (no session)</body></html>");
out.close();
return;
}
if (!mud.getStore().isConnected()) {
res.setContentType("text/html;charset=UTF-8");
out.println("<html><body>Not Connected To Store</body></html>");
out.close();
return;
}
// mux that takes a GET request, based on parameters figures
// out what it should do, and routes it to the
// appropriate method
// get url parameters
String msgStr = req.getParameter("message");
String logout = req.getParameter("logout");
String compose = req.getParameter("compose");
String part = req.getParameter("part");
int msgNum = -1;
int partNum = -1;
// process url params
if (msgStr != null) {
// operate on message "msgStr"
msgNum = Integer.parseInt(msgStr);
if (part == null) {
// display message "msgStr"
res.setContentType("text/html;charset=UTF-8");
displayMessage(mud, req, out, msgNum);
} else if (part != null) {
// display part "part" in message "msgStr"
partNum = Integer.parseInt(part);
displayPart(mud, msgNum, partNum, out, res);
}
} else if (compose != null) {
// display compose form
compose(mud, res, out);
} else if (logout != null) {
// process logout
try {
mud.getFolder().close(false);
mud.getStore().close();
ses.invalidate();
out.println("<html><body>Logged out OK</body></html>");
} catch (MessagingException mex) {
out.println(mex.toString());
}
} else {
// display headers
displayHeaders(mud, req, out);
}
}
/* main method to display messages */
private void displayMessage(MailUserData mud, HttpServletRequest req,
ServletOutputStream out, int msgNum) throws IOException {
out.println("<html>");
out.println("<HEAD><TITLE>JavaMail Servlet</TITLE></HEAD>");
out.println("<BODY bgcolor=\"#ccccff\">");
out.print("<center><font face=\"Arial,Helvetica\" ");
out.println("font size=\"+3\"><b>");
out.println("Message " + (msgNum + 1) + " in folder "
+ mud.getStore().getURLName() + "/INBOX</b></font></center><p>");
try {
Message msg = mud.getFolder().getMessage(msgNum);
// first, display this message's headers
displayMessageHeaders(mud, msg, out);
// and now, handle the content
Object o = msg.getContent();
// if (o instanceof String) {
if (msg.isMimeType("text/plain")) {
out.println("<pre>");
out.println((String) o);
out.println("</pre>");
// } else if (o instanceof Multipart){
} else if (msg.isMimeType("multipart/*")) {
Multipart mp = (Multipart) o;
int cnt = mp.getCount();
for (int i = 0; i < cnt; i++) {
displayPart(mud, msgNum, mp.getBodyPart(i), i, req, out);
}
} else {
out.println(msg.getContentType());
}
} catch (MessagingException mex) {
out.println(mex.toString());
}
out.println("</BODY></html>");
out.close();
}
/**
* This method displays a message part. <code>text/plain</code> content
* parts are displayed inline. For all other parts, a URL is generated and
* displayed; clicking on the URL brings up the part in a separate page.
*/
private void displayPart(MailUserData mud, int msgNum, Part part,
int partNum, HttpServletRequest req, ServletOutputStream out)
throws IOException {
if (partNum != 0)
out.println("<p><hr>");
try {
String sct = part.getContentType();
if (sct == null) {
out.println("invalid part");
return;
}
ContentType ct = new ContentType(sct);
if (partNum != 0)
out.println("<b>Attachment Type:</b> " + ct.getBaseType()
+ "<br>");
if (ct.match("text/plain")) {
// display text/plain inline
out.println("<pre>");
out.println((String) part.getContent());
out.println("</pre>");
} else {
// generate a url for this part
String s;
if ((s = part.getFileName()) != null)
out.println("<b>Filename:</b> " + s + "<br>");
s = null;
if ((s = part.getDescription()) != null)
out.println("<b>Description:</b> " + s + "<br>");
out.println("<a href=\"" + HttpUtils.getRequestURL(req)
+ "?message=" + msgNum + "&part=" + partNum
+ "\">Display Attachment</a>");
}
} catch (MessagingException mex) {
out.println(mex.toString());
}
}
/**
* This method gets the stream from for a given msg part and pushes it out
* to the browser with the correct content type. Used to display attachments
* and relies on the browser's content handling capabilities.
*/
private void displayPart(MailUserData mud, int msgNum, int partNum,
ServletOutputStream out, HttpServletResponse res)
throws IOException {
Part part = null;
try {
Message msg = mud.getFolder().getMessage(msgNum);
Multipart mp = (Multipart) msg.getContent();
part = mp.getBodyPart(partNum);
String sct = part.getContentType();
if (sct == null) {
out.println("invalid part");
return;
}
ContentType ct = new ContentType(sct);
res.setContentType(ct.getBaseType());
InputStream is = part.getInputStream();
int i;
while ((i = is.read()) != -1)
out.write(i);
out.flush();
out.close();
} catch (MessagingException mex) {
out.println(mex.toString());
}
}
/**
* This is a utility message that pretty-prints the message headers for
* message that is being displayed.
*/
private void displayMessageHeaders(MailUserData mud, Message msg,
ServletOutputStream out) throws IOException {
try {
out.println("<b>Date:</b> " + msg.getSentDate() + "<br>");
Address[] fr = msg.getFrom();
if (fr != null) {
boolean tf = true;
out.print("<b>From:</b> ");
for (int i = 0; i < fr.length; i++) {
out.print(((tf) ? " " : ", ") + getDisplayAddress(fr[i]));
tf = false;
}
out.println("<br>");
}
Address[] to = msg.getRecipients(Message.RecipientType.TO);
if (to != null) {
boolean tf = true;
out.print("<b>To:</b> ");
for (int i = 0; i < to.length; i++) {
out.print(((tf) ? " " : ", ") + getDisplayAddress(to[i]));
tf = false;
}
out.println("<br>");
}
Address[] cc = msg.getRecipients(Message.RecipientType.CC);
if (cc != null) {
boolean cf = true;
out.print("<b>CC:</b> ");
for (int i = 0; i < cc.length; i++) {
out.print(((cf) ? " " : ", ") + getDisplayAddress(cc[i]));
cf = false;
}
out.println("<br>");
}
out.print("<b>Subject:</b> "
+ ((msg.getSubject() != null) ? msg.getSubject() : "")
+ "<br>");
} catch (MessagingException mex) {
out.println(msg.toString());
}
}
/**
* This method displays the URL's for the available commands and the INBOX
* headerlist
*/
private void displayHeaders(MailUserData mud, HttpServletRequest req,
ServletOutputStream out) throws IOException {
SimpleDateFormat df = new SimpleDateFormat("EE M/d/yy");
out.println("<html>");
out.println("<HEAD><TITLE>JavaMail Servlet</TITLE></HEAD>");
out.println("<BODY bgcolor=\"#ccccff\"><hr>");
out.print("<center><font face=\"Arial,Helvetica\" font size=\"+3\">");
out.println("<b>Folder " + mud.getStore().getURLName()
+ "/INBOX</b></font></center><p>");
// URL's for the commands that are available
out.println("<font face=\"Arial,Helvetica\" font size=\"+3\"><b>");
out.println("<a href=\"" + HttpUtils.getRequestURL(req)
+ "?logout=true\">Logout</a>");
out.println("<a href=\"" + HttpUtils.getRequestURL(req)
+ "?compose=true\" target=\"compose\">Compose</a>");
out.println("</b></font>");
out.println("<hr>");
// List headers in a table
out.print("<table cellpadding=1 cellspacing=1 "); // table
out.println("width=\"100%\" border=1>"); // settings
// sender column header
out.println("<tr><td width=\"25%\" bgcolor=\"ffffcc\">");
out.println("<font face=\"Arial,Helvetica\" font size=\"+1\">");
out.println("<b>Sender</b></font></td>");
// date column header
out.println("<td width=\"15%\" bgcolor=\"ffffcc\">");
out.println("<font face=\"Arial,Helvetica\" font size=\"+1\">");
out.println("<b>Date</b></font></td>");
// subject column header
out.println("<td bgcolor=\"ffffcc\">");
out.println("<font face=\"Arial,Helvetica\" font size=\"+1\">");
out.println("<b>Subject</b></font></td></tr>");
try {
Folder f = mud.getFolder();
int msgCount = f.getMessageCount();
Message m = null;
// for each message, show its headers
for (int i = 1; i <= msgCount; i++) {
m = f.getMessage(i);
// if message has the DELETED flag set, don't display it
if (m.isSet(Flags.Flag.DELETED))
continue;
// from
out.println("<tr valigh=middle>");
out.print("<td width=\"25%\" bgcolor=\"ffffff\">");
out.println("<font face=\"Arial,Helvetica\">"
+ ((m.getFrom() != null) ? m.getFrom()[0].toString()
: "") + "</font></td>");
// date
out.print("<td nowrap width=\"15%\" bgcolor=\"ffffff\">");
out.println("<font face=\"Arial,Helvetica\">"
+ df.format((m.getSentDate() != null) ? m.getSentDate()
: m.getReceivedDate()) + "</font></td>");
// subject & link
out.print("<td bgcolor=\"ffffff\">");
out.println("<font face=\"Arial,Helvetica\">"
+ "<a href=\""
+ HttpUtils.getRequestURL(req)
+ "?message="
+ i
+ "\">"
+ ((m.getSubject() != null) ? m.getSubject()
: "<i>No Subject</i>") + "</a>"
+ "</font></td>");
out.println("</tr>");
}
} catch (MessagingException mex) {
out.println("<tr><td>" + mex.toString() + "</td></tr>");
mex.printStackTrace();
}
out.println("</table>");
out.println("</BODY></html>");
out.flush();
out.close();
}
/**
* This method handles the request when the user hits the <i>Compose</i>
* link. It send the compose form to the browser.
*/
private void compose(MailUserData mud, HttpServletResponse res,
ServletOutputStream out) throws IOException {
res.setContentType("text/html;charset=UTF-8");
out.println(composeForm);
out.close();
}
/**
* This method processes the send request from the compose form
*/
private void send(HttpServletRequest req, HttpServletResponse res,
ServletOutputStream out, HttpSession ssn) throws IOException {
//req.setCharacterEncoding("UTF-8");
String to = req.getParameter("to");
String cc = req.getParameter("cc");
String subj = req.getParameter("subject");
String text = req.getParameter("text");
System.out.println(" Request characterEncoding: " + req.getCharacterEncoding());
System.out.println("..subject : "+ subj);
System.out.println("..text : "+ text);
try {
final MailUserData mud = getMUD(ssn);
if (mud == null)
throw new Exception("trying to send, but not logged in");
//MimeMessage msg = new MimeMessage(sess);
MimeMessage msg = new MimeMessage( mud.getSession());
InternetAddress[] toAddrs = null, ccAddrs = null;
if (to != null) {
toAddrs = InternetAddress.parse(to, false);
msg.setRecipients(Message.RecipientType.TO, toAddrs);
//TODO: TEST
Address[] recipients = msg.getAllRecipients();
for (Address recipient : recipients) {
System.out.println("... recipient : "
+ recipient.toString());
}
} else
throw new MessagingException("No \"To\" address specified");
if (cc != null) {
ccAddrs = InternetAddress.parse(cc, false);
msg.setRecipients(Message.RecipientType.CC, ccAddrs);
}
if (subj != null)
msg.setSubject(subj, "UTF-8");
URLName u = mud.getURLName();
// msg.setFrom(new InternetAddress(u.getUsername() + "@" +
// u.getHost()));
msg.setFrom(new InternetAddress(u.getUsername()));
if (text != null)
msg.setText(text, "UTF-8");
// msg.setSubject("Hello JavaMail:한글제목", "utf-8");
// msg.setText("Welcome to JavaMail:한글메시지 ", "utf-8");
Transport.send(msg);
out.println("<h1>Message sent successfully</h1></body></html>");
out.close();
} catch (Exception mex) {
out.println("<h1>Error sending message.</h1>");
out.println(mex.toString());
out.println("<br></body></html>");
}
}
// utility method; returns a string suitable for msg header display
private String getDisplayAddress(Address a) {
String pers = null;
String addr = null;
if (a instanceof InternetAddress
&& ((pers = ((InternetAddress) a).getPersonal()) != null)) {
addr = pers + " " + "<" + ((InternetAddress) a).getAddress()
+ ">";
} else
addr = a.toString();
return addr;
}
// utility method; retrieve the MailUserData
// from the HttpSession and return it
private MailUserData getMUD(HttpSession ses) throws IOException {
MailUserData mud = null;
if (ses == null) {
return null;
} else {
// if ((mud = (MailUserData) ses.getValue("javamailservlet")) == null) {
if ((mud = (MailUserData) ses.getAttribute("javamailservlet")) == null) {
return null;
}
}
return mud;
}
public String getServletInfo() {
return "A mail reader servlet";
}
/**
* This is the HTML code for the compose form. Another option would have
* been to use a separate html page.
*/
private static String composeForm = "<HTML><HEAD><META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"> <TITLE>JavaMail Compose</TITLE></HEAD><BODY BGCOLOR=\"#CCCCFF\"><FORM ACTION=\"javamail\" METHOD=\"POST\"><input type=\"hidden\" name=\"send\" value=\"send\"><P ALIGN=\"CENTER\"><B><FONT SIZE=\"4\" FACE=\"Verdana, Arial, Helvetica\">JavaMail Compose Message</FONT></B><P><TABLE BORDER=\"0\" WIDTH=\"100%\"><TR><TD WIDTH=\"16%\" HEIGHT=\"22\"> <P ALIGN=\"RIGHT\"><B><FONT FACE=\"Verdana, Arial, Helvetica\">To:</FONT></B></TD><TD WIDTH=\"84%\" HEIGHT=\"22\"><INPUT TYPE=\"TEXT\" NAME=\"to\" SIZE=\"30\"> <FONT SIZE=\"1\" FACE=\"Verdana, Arial, Helvetica\"> (separate addresses with commas)</FONT></TD></TR><TR><TD WIDTH=\"16%\"><P ALIGN=\"RIGHT\"><B><FONT FACE=\"Verdana, Arial, Helvetica\">CC:</FONT></B></TD><TD WIDTH=\"84%\"><INPUT TYPE=\"TEXT\" NAME=\"cc\" SIZE=\"30\"> <FONT SIZE=\"1\" FACE=\"Verdana, Arial, Helvetica\"> (separate addresses with commas)</FONT></TD></TR><TR><TD WIDTH=\"16%\"><P ALIGN=\"RIGHT\"><B><FONT FACE=\"Verdana, Arial, Helvetica\">Subject:</FONT></B></TD><TD WIDTH=\"84%\"><INPUT TYPE=\"TEXT\" NAME=\"subject\" SIZE=\"55\"></TD></TR><TR><TD WIDTH=\"16%\"> </TD><TD WIDTH=\"84%\"><TEXTAREA NAME=\"text\" ROWS=\"15\" COLS=\"53\"></TEXTAREA></TD></TR><TR><TD WIDTH=\"16%\" HEIGHT=\"32\"> </TD><TD WIDTH=\"84%\" HEIGHT=\"32\"><INPUT TYPE=\"SUBMIT\" NAME=\"Send\" VALUE=\"Send\"><INPUT TYPE=\"RESET\" NAME=\"Reset\" VALUE=\"Reset\"></TD></TR></TABLE></FORM></BODY></HTML>";
}
/**
* This class is used to store session data for each user's session. It is
* stored in the HttpSession.
*/
class MailUserData {
URLName url;
Session session;
Store store;
Folder folder;
public MailUserData(URLName urlname) {
url = urlname;
}
public URLName getURLName() {
return url;
}
public Session getSession() {
return session;
}
public void setSession(Session s) {
session = s;
}
public Store getStore() {
return store;
}
public void setStore(Store s) {
store = s;
}
public Folder getFolder() {
return folder;
}
public void setFolder(Folder f) {
folder = f;
}
}