/* * Copyright (c) 1998-2011 Oracle and/or its affiliates. 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 Oracle 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.Part; 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 { // 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"); out.println("<html><body bgcolor=\"#CCCCFF\">"); if (send != null) { // process message sending send(req, res, out, ssn); } else { // initial login // create MailUserData mud = new MailUserData(url); ssn.putValue("javamailservlet", mud); try { Properties props = System.getProperties(); props.put("mail.smtp.host", host); Session session = Session.getDefaultInstance(props, null); session.setDebug(false); Store store = session.getStore(url); store.connect(); 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 { 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"); out.println("<html><body>Please Login (no session)</body></html>"); out.close(); return; } if (!mud.getStore().isConnected()) { res.setContentType("text/html"); 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"); displayMessage(mud, req, out, msgNum); } else { // 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"); 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 { String to = req.getParameter("to"); String cc = req.getParameter("cc"); String subj = req.getParameter("subject"); String text = req.getParameter("text"); try { MailUserData mud = getMUD(ssn); if (mud == null) throw new Exception("trying to send, but not logged in"); Message msg = new MimeMessage(mud.getSession()); InternetAddress[] toAddrs = null, ccAddrs = null; if (to != null) { toAddrs = InternetAddress.parse(to, false); msg.setRecipients(Message.RecipientType.TO, toAddrs); } 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); URLName u = mud.getURLName(); msg.setFrom(new InternetAddress(u.getUsername() + "@" + u.getHost())); if (text != null) msg.setText(text); 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){ 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><TITLE>JavaMail Compose</TITLE></HEAD><BODY BGCOLOR=\"#CCCCFF\"><FORM ACTION=\"/servlet/JavaMailServlet\" 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; } }