Javamail API虽然功能封装的比较完整,但是要写一个能正确显示复杂邮件的程序还有很多逻辑和细节要处理。下面是我最近做一个webmail时整理的Servlet,基本上可以正确的读取text,HTML,HTML中显示图片及附件。在本servlet中也简单处理了常见的中文问题,包括主题、附件、HTML图片中文、email Address中文。总体感觉有两个难点:1、附件和网页图片的抓取,需要定位数节点nodeid,光用partid是不行的;2、中文分两种情况Base64和客户端服务器端编码不一致。本程序中实现了3种displayPart()的方法,具体情况不同结合使用效率更高。本程序还有一个未处理的地方就是我在做nodeid的时候最多算10个。当然还有其他问题欢迎指正,来出是为了给后来的初学者作个参考例子,少走弯路。
1 import java.io.IOException;
2 import java.io.InputStream;
3 import java.io.UnsupportedEncodingException;
4 import java.util.HashMap;
5 import javax.mail.Folder;
6 import javax.mail.Message;
7 import javax.mail.MessagingException;
8 import javax.mail.Multipart;
9 import javax.mail.Part;
10 import javax.mail.Store;
11 import javax.mail.internet.InternetAddress;
12 import javax.mail.internet.MimeUtility;
13 import javax.servlet.ServletException;
14 import javax.servlet.ServletOutputStream;
15 import javax.servlet.http.HttpServletRequest;
16 import javax.servlet.http.HttpServletResponse;
17 import javax.servlet.http.HttpSession;
18 import chunwei.mail.Login;
19 import chunwei.mail.MailUserData;
20 /**
21 * Servlet implementation class for Servlet: MailServlet
22 * Author: luchunwei Email: luchunwei@gmail.com
23 */
24 public class MailNode extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
25 private static final long serialVersionUID = 1L;
26 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
27 nodeid="";
28 node="0";
29 currentnodeid=0;
30 url=request.getRequestURL().toString();
31 HttpSession ses=request.getSession();
32 MailUserData mud=(MailUserData)ses.getAttribute("mud");
33 ServletOutputStream out=response.getOutputStream();
34 response.setContentType("text/html;charset=GB2312");
35 int msgid=-1,partid=-1;//msgdi:邮件编号;partid:MultiPart Message中part的编号。
36 String partname=null; //图片或附件的文件名
37 String nodepara=null;//节点编号,如1-2-1-0, 他以便层层剥入
38 if (request.getParameter("msgid")!=null)
39 msgid=Integer.parseInt(request.getParameter("msgid"));
40 msgidStr="msgid="+msgid;
41 if (request.getParameter("partid")!=null)
42 partid=Integer.parseInt(request.getParameter("partid"));
43 if (request.getParameter("partname")!=null)
44 partname=new String(request.getParameter("partname").getBytes("ISO-8859-1"),"GB2312");
45 if (request.getParameter("node")!=null)
46 nodepara=request.getParameter("node");
47 System.out.println(nodepara);
48 //System.out.println(msgid+":"+partid+":"+partname);
49 if (partname!=null){
50 //displayImages
51 try {
52 displayPart(partname,response,out);
53 } catch (MessagingException e) {
54 e.printStackTrace();
55 } catch (IOException e) {
56 e.printStackTrace();
57 }
58 return;
59 }
60 //--------------------------
61 if (mud==null){
62 Login login=new Login("imap","mail.server.com",-1,"user","password");
63 login.login();
64 if (login.getResult()==1){
65 HttpSession session = request.getSession();
66 session.setMaxInactiveInterval(3600);
67 session.setAttribute("mud",login.getMud());
68 }
69 mud=(MailUserData)ses.getAttribute("mud");
70 }
71 //---------------------------
72 if (mud==null){
73 out.print("<error>Login First(No Session)</error>");
74 } else{
75 //Folder folder=mud.getFolder();
76 try {
77 //------------------------
78 Store store=mud.getStore();
79 Folder folder=store.getFolder("INBOX");
80 folder.open(Folder.READ_ONLY);
81 //------------------------
82 Message m=folder.getMessage(msgid);
83 //if(partid==-1){
84 if (nodepara==null){
85 //if(!imgs.isEmpty())imgs.clear();
86 messageHtml="";
87 attachment="";
88 recipients=getAllgetRecipients(m);
89 out.print(displayMessage(request,m,partid));
90 } else{
91 displayPart(m,nodepara,response,out);
92 }
93 } catch (MessagingException e) {
94 e.printStackTrace();
95 } catch (IOException e) {
96 e.printStackTrace();
97 } catch (Exception e) {
98 e.printStackTrace();
99 }
100 }
101 }
102 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
103 doGet(request,response);
104 }
105 String stdUrl="";
106 String url="";
107 String msgidStr="";
108 String messageHtml="";
109 String attachment="";
110 String recipients="";
111 String nodeid="";
112 int currentnodeid=0;
113 String node="";
114 HashMap<String,Part> imgs=new HashMap<String,Part>();
115 public String displayMessage(HttpServletRequest request,Part p,int partid) throws Exception{
116 //System.out.println("Type:"+p.getContentType());
117 if (currentnodeid==1&&!node.endsWith("0")){
118 nodeid=nodeid.substring(0,(nodeid.length()-2));
119 }
120 node=nodeid+currentnodeid;
121 System.out.println(node);
122 if (p.isMimeType("multipart/*")){
123 nodeid+=currentnodeid+"-";
124 Multipart mp=(Multipart) p.getContent();
125 int cnt=mp.getCount();
126 String mpct=mp.getContentType().toLowerCase();
127 for (int i=0;
128 i<cnt;
129 i++){
130 if (mpct.startsWith("multipart/alternative")&&mp.getBodyPart(i).getContentType().toLowerCase().startsWith("text/plain"))continue;
131 currentnodeid=i;
132 displayMessage(request,mp.getBodyPart(i),i);
133 }
134 }
135 if (p.isMimeType("text/plain")||p.isMimeType("text/html")){
136 if (messageHtml=="") {
137 messageHtml=(String)p.getContent();
138 //System.out.println(messageHtml);
139 } else {
140 messageHtml=messageHtml+"<HR/>"+(String)p.getContent();
141 //System.out.println(messageHtml);
142 }
143 } else if (p.isMimeType("message/rfc822")) {
144 //Nested Message
145 //displayMessage(request,(Part)p.getContent(),partid);
146 } else{
147 if (node.length()>2) node=node.substring(2);
148 System.out.println(node);
149 String disposition=p.getDisposition();
150 //System.out.println("disposition:"+disposition);
151 if (disposition!=null&&disposition.equalsIgnoreCase(Part.ATTACHMENT)){
152 String filename=getFileName(p);
153 //imgs.put(filename,p);
154 //attachment全部放入内存,会造成内存膨胀;若及时清空又造成Back回来的页面访问不到Attachment
155 //attachment+=","+"<a href='"+url+"/"+filename+"?"+msgidStr+"&partid="+partid+"'>"+filename+"</a>";
156 attachment+=","+"<a href='"+url+"/"+filename+"?"+msgidStr+"&node="+node+"'>"+filename+"</a>";
157 //attachment+=","+"<a href='"+url+"/"+filename+"?"+"&partname="+getFileName(p)+"'>"+filename+"</a>";
158 //System.out.println(attachment);
159 } else{
160 //if(disposition!=null&&disposition.equalsIgnoreCase(Part.INLINE)){
161 if (getCid(p)!=null) {
162 //System.out.println("Enter Replace");
163 imgs.put(getFileName(p),p);
164 //String uri=url+"?"+msgidStr+"&partid="+partid;
165 String uri=url+"?"+msgidStr+"&node="+node;
166 //String uri=url+"?"+"&partname="+getFileName(p);
167 String t=messageHtml.substring(messageHtml.indexOf(getCid(p))-1);
168 if (!(t.startsWith("\"")||t.startsWith("\'"))){
169 uri="'"+uri+"'";
170 }
171 messageHtml=messageHtml.replace(getCid(p),uri);
172 //System.out.println("cid:"+getCid(p));
173 //System.out.println(uri);
174 }
175 }
176 }
177 return messageHtml+"attachhncwx="+attachment+recipients;
178 }
179 public void displayPart(Message m,String node,HttpServletResponse response,ServletOutputStream out)
180 throws MessagingException, IOException{
181 Part part = getPart(m,node);
182 String sct = part.getContentType();
183 response.setContentType(sct);
184 outPut(part,out);
185 }
186 private Part getPart(Part m, String nodes) throws NumberFormatException, MessagingException, IOException {
187 if (node==null)return m;
188 String node=nodes.substring(0,1);
189 System.out.println(nodes+" : "+node);
190 int nid=Integer.parseInt(node);
191 if (m.getContent()==null)System.out.print("no content");
192 Part p=((Multipart)m.getContent()).getBodyPart(nid);
193 if (nodes.length()>2)nodes=nodes.substring(2);
194 else {
195 if (nodes.length()==1)nodes="";
196 }
197 if (nodes.length()>0)p=getPart(p,nodes);
198 return p;
199 }
200 public void displayPart(String partname,HttpServletResponse response, ServletOutputStream out) throws MessagingException, IOException{
201 //System.out.println(imgs.keySet()+":"+partname);
202 Part part=imgs.get(partname);
203 String ct=part.getContentType();
204 if (ct!=null) response.setContentType(ct);
205 //=====Start push Stream into out
206 InputStream in=part.getInputStream();
207 ByteArrayOutputStream bos=new ByteArrayOutputStream();
208 byte [] buffer=new byte[8192];
209 int count=0;
210 while ((count=in.read(buffer))>=0) bos.write(buffer,0,count);
211 in .close();
212 try{
213 out.write(bos.toByteArray());
214 out.flush();
215 } catch(Exception e){
216 }
217 out.close();
218 //=====End
219 }
220 public void displayPart(Message m,int partid,HttpServletResponse response, ServletOutputStream out) throws MessagingException, IOException{
221 Multipart mp = (Multipart)m.getContent();
222 Part part = mp.getBodyPart(partid);
223 String sct = part.getContentType();
224 // ContentType ct = new ContentType(sct);
225 response.setContentType(sct);
226 if (sct == null) {
227 out.println("invalid part");
228 return;
229 }
230 //=====Start push Stream into out
231 InputStream in=part.getInputStream();
232 ByteArrayOutputStream bos=new ByteArrayOutputStream();
233 byte [] buffer=new byte[8192];
234 int count=0;
235 while ((count=in.read(buffer))>=0) bos.write(buffer,0,count);
236 in .close();
237 try{
238 out.write(bos.toByteArray());
239 out.flush();
240 } catch(Exception e){
241 }
242 out.close();
243 //=====End
244 }
245 private String getFileName(Part p) throws MessagingException, UnsupportedEncodingException{
246 //System.out.println("filename:");
247 String filename=p.getFileName();
248 if (filename==null)return null;
249 filename=new String(filename.getBytes("ISO-8859-1"),"GB2312");
250 int indexStart=filename.toUpperCase().indexOf("=?GB");
251 if (indexStart>-1){
252 filename=filename.substring(0,indexStart)+MimeUtility.decodeText(filename.substring(indexStart));
253 }
254 return filename;
255 }
256 private String getCid(Part p) throws MessagingException{
257 String cidraw=null,cid=null;
258
259 String [] headers=p.getHeader("Content-id");
260 if (headers!=null && headers.length>0) {
261 cidraw=headers[0];
262 } else{
263 return null;
264 }
265 if (cidraw.startsWith("<")&&cidraw.endsWith(">")) {
266 cid="cid:"+cidraw.substring(1,cidraw.length()-1);
267 } else {
268 cid="cid:"+cidraw;
269 }
270 return cid;
271 }
272 /**
273 * 获得邮件的收件人,抄送,和密送的地址和姓名,根据所传递的参数的不同 "to"----收件人 "cc"---抄送人地址 "bcc"---密送人地址
274 * @throws Exception
275 */
276 private String getAllgetRecipients(Message m) throws Exception{
277 return "mailaddrTo=" +getRecipients(m,"TO")
278 +"mailaddrCc="+getRecipients(m,"CC")
279 +"mailaddrBcc="+getRecipients(m,"BCC");
280 }
281 private String getRecipients(Message m,String type) throws Exception {
282 StringBuffer mailaddr = new StringBuffer("");
283 String addtype = type.toUpperCase();
284 InternetAddress[] address = null;
285 if (addtype.equals("TO")) {
286 address = (InternetAddress[]) m.getRecipients(Message.RecipientType.TO);
287 } else if (addtype.equals("CC")) {
288 address = (InternetAddress[]) m.getRecipients(Message.RecipientType.CC);
289 } else {
290 address = (InternetAddress[]) m.getRecipients(Message.RecipientType.BCC);
291 }
292 if (address != null) {
293 for (int i = 0;
294 i < address.length;
295 i++) {
296 String email = address[i].getAddress();
297 if (email == null)
298 email = "";
299 else {
300 email = MimeUtility.decodeText(email);
301 }
302 String personal = address[i].getPersonal();
303 if (personal == null)
304 personal = "";
305 else {
306 personal = MimeUtility.decodeText(personal);
307 }
308 mailaddr.append("\""+personal+"\" ");
309 mailaddr.append("<");
310 mailaddr.append(email);
311 mailaddr.append(">");
312 mailaddr.append(",");
313 }
314 }
315 if (mailaddr.length()>0)mailaddr.deleteCharAt(mailaddr.length()-1);
316 return mailaddr.toString();
317 }
318 private void outPut(Part part,ServletOutputStream out) throws IOException, MessagingException{
319 //=====Start push Stream into out
320 InputStream in=part.getInputStream();
321 ByteArrayOutputStream bos=new ByteArrayOutputStream();
322 byte [] buffer=new byte[8192];
323 int count=0;
324 while ((count=in.read(buffer))>=0) bos.write(buffer,0,count);
325 in .close();
326 try{
327 out.write(bos.toByteArray());
328 out.flush();
329 } catch(Exception e){
330 }
331 out.close();
332 //=====End
333 }
334 }