本節摘要:本節主要簡單介紹一下javamail插件的使用
引入:最近項目中要做一個簡單的郵件功能,即從前台輸入郵件內容,去配置文件中讀取發件人、收件人等信息后,然后發送郵件到指定的郵箱,其中收件人和抄送人可以有多個,基於這個需求,查詢了相關資料,決定采用javamail這個插件來實現。
preparation:
1.JavaMail的介紹
JavaMail,顧名思義,提供給開發者處理電子郵件相關的編程接口。它是Sun發布的用來處理email的API。它可以方便地執行一些常用的郵件傳輸。
雖然JavaMail是Sun的API之一,但它目前還沒有被加在標准的java開發工具包中(Java Development Kit),這就意味着你在使用前必須另外下載JavaMail文件。除此以外,你還需要有Sun的JavaBeans Activation Framework (JAF)。JavaBeans Activation Framework的運行很復雜,在這里簡單的說就是JavaMail的運行必須得依賴於它的支持。在Windows 2000下使用需要指定這些文件的路徑,在其它的操作系統上也類似。
2.下載jar包
網上有下載鏈接,但是這里我還是把jar包給上傳
dom4j.jar 這個jar就不提供下載資源了
3.項目環境
system:win7 myeclipse:6.5 tomcat:5.0 JDK:編譯和運行都是1.4
為了方便,還是在之前的UpDown項目下運行的,本次用到的文件只有sendmail包下的文件。
4.class&method
請參考:http://www.jspcn.net/htmlnews/1150019680500144.html
start
導入javamail、JAF、dom4j的jar包,然后新建對應的文件如下:
Encrypt.jar 主要是用於對密碼進行加密和解密

1 package sendmail;
2
3 /**
4 * Module: Encrypt.java
5 * Description: 對密碼進行加密和解密
6 * Company:
7 * Author: ptp
8 * Date: Mar 6, 2012
9 */
10 public class Encrypt
11 {
12
13 public static final int pass1 = 10;
14 public static final int pass2 = 1;
15
16 public Encrypt()
17 {
18 }
19
20 /**
21 * @Title: DoEncrypt
22 * @Description: 對密碼進行加密的方法
23 * @param @param str
24 * @param @return 設定文件
25 * @return String 返回類型
26 * @throws
27 */
28 public static String DoEncrypt(String str)
29 {
30 StringBuffer enStrBuff = new StringBuffer();
31 for (int i = 0; i < str.length(); i++)
32 {
33 int tmpch = str.charAt(i);
34 tmpch ^= 1;
35 tmpch ^= 0xa;
36 enStrBuff.append(Integer.toHexString(tmpch));
37 }
38
39 return enStrBuff.toString().toUpperCase();
40 }
41
42 /**
43 * @Title: DoDecrypt
44 * @Description: 對密碼進行解密的方法
45 * @param @param str
46 * @param @return 設定文件
47 * @return String 返回類型
48 * @throws
49 */
50 public static String DoDecrypt(String str)
51 {
52 String deStr = str.toLowerCase();
53 StringBuffer deStrBuff = new StringBuffer();
54 for (int i = 0; i < deStr.length(); i += 2)
55 {
56 String subStr = deStr.substring(i, i + 2);
57 int tmpch = Integer.parseInt(subStr, 16);
58 tmpch ^= 1;
59 tmpch ^= 0xa;
60 deStrBuff.append((char)tmpch);
61 }
62
63 return deStrBuff.toString();
64 }
65
66 public static void main(String args[])
67 {
68 String source = "123456";
69 String s = DoEncrypt(source);
70 System.out.println("de=" + s);
71
72 source = DoDecrypt(s);
73 System.out.println("en=" + source);
74
75 }
76 }
MailInfo.java javabean定義郵件需要的字段以及對應的get和set方法

1 package sendmail;
2
3 /**
4 *Module: MailInfo.java
5 *Description: 定義發送郵件的所有字段的javabean
6 *Company:
7 *Author: ptp
8 *Date: Mar 1, 2012
9 */
10 public class MailInfo{
11 private String host;// 郵件服務器域名或IP
12 private String from;// 發件人
13 private String to;// 收件人
14 private String cc;// 抄送人
15 private String username;// 發件人用戶名
16 private String password;// 發件人密碼
17 private String title;// 郵件的主題
18 private String content;// 郵件的內容
19
20 public String getHost() {
21 return host;
22 }
23 public void setHost(String host) {
24 this.host = host;
25 }
26 public String getFrom() {
27 return from;
28 }
29 public void setFrom(String from) {
30 this.from = from;
31 }
32 public String getTo() {
33 return to;
34 }
35 public void setTo(String to) {
36 this.to = to;
37 }
38 public String getCc() {
39 return cc;
40 }
41 public void setCc(String cc) {
42 this.cc = cc;
43 }
44 public String getUsername() {
45 return username;
46 }
47 public void setUsername(String username) {
48 this.username = username;
49 }
50 public String getPassword() {
51 return password;
52 }
53 public void setPassword(String password) {
54 this.password = password;
55 }
56 public String getTitle() {
57 return title;
58 }
59 public void setTitle(String title) {
60 this.title = title;
61 }
62 public String getContent() {
63 return content;
64 }
65 public void setContent(String content) {
66 this.content = content;
67 }
68
69 }
MyAuthenticator.java 用於對郵件授權

1 package sendmail;
2
3 /**
4 *Module: MailInfo.java
5 *Description: 郵件授權類
6 *Company:
7 *Author: ptp
8 *Date: Mar 6, 2012
9 */
10 import javax.mail.PasswordAuthentication;
11
12 public class MyAuthenticator extends javax.mail.Authenticator {
13 private String strUser;
14 private String strPwd;
15
16 public MyAuthenticator(String user, String password) {
17 this.strUser = user;
18 this.strPwd = password;
19 }
20
21 protected PasswordAuthentication getPasswordAuthentication() {
22 return new PasswordAuthentication(strUser, strPwd);
23 }
24 }
SendMail.java 發送郵件的封裝類
先讀取xml配置文件,然后解析xml文件,最后取得配置文件的值封裝完成后發郵件

1 package sendmail;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.io.FileNotFoundException;
7 import java.io.IOException;
8 import java.io.InputStreamReader;
9 import java.io.UnsupportedEncodingException;
10 import java.util.Properties;
11 import javax.mail.Message;
12 import javax.mail.MessagingException;
13 import javax.mail.Session;
14 import javax.mail.Transport;
15 import javax.mail.internet.AddressException;
16 import javax.mail.internet.InternetAddress;
17 import javax.mail.internet.MimeMessage;
18 import org.apache.commons.logging.Log;
19 import org.apache.commons.logging.LogFactory;
20 import org.dom4j.Document;
21 import org.dom4j.DocumentException;
22 import org.dom4j.DocumentHelper;
23 import org.dom4j.Element;
24
25 /**
26 * Module: SendMail.java
27 * Description: 發送郵件
28 * Company:
29 * Author: ptp
30 * Date: Mar 1, 2012
31 */
32
33 public class SendMail {
34
35 private static final Log log = LogFactory.getLog(SendMail.class);
36
37 // 配置文件xml的路徑
38 private final static String XML_PATH = "src" + File.separator + "sendmail"
39 + File.separator + "SendMail.xml";
40
41 //xml文件中字段對應的javabean對象
42 private static MailInfo mailInfo = new MailInfo();
43
44 /**
45 * <p>Title: readXML</p>
46 * <p>Description:讀取xml文件,把文件內容以字符串形式輸出</p>
47 * @param xmlPath 配置文件的路徑
48 * @return
49 * @throws Exception
50 */
51 private String readXML(String xmlPath) throws Exception {
52 log.debug("xmlPath="+xmlPath);
53
54 String fileContent = "";
55 File file = new File(xmlPath);
56 if (file.isFile() && file.exists()) {
57 try {
58 InputStreamReader read = new InputStreamReader(
59 new FileInputStream(file), "UTF-8");
60 BufferedReader reader = new BufferedReader(read);
61 String line;
62 try {
63 while ((line = reader.readLine()) != null) {
64 fileContent += line;
65 }
66 reader.close();
67 read.close();
68 } catch (IOException e) {
69 e.printStackTrace();
70 }
71 } catch (UnsupportedEncodingException e) {
72 e.printStackTrace();
73 } catch (FileNotFoundException e) {
74 e.printStackTrace();
75 }
76 }else{
77 throw new Exception("config目錄下的配置文件SendMail.xml不存在,請檢查");
78 }
79 log.debug("xml="+fileContent);
80 return fileContent;
81 }
82
83 /**
84 * <p>Title: parseXML</p>
85 * <p>Description:發送郵件給指定的收件人和抄送人,同時進行一些簡單的校驗判斷,如必填項的字段、type的值</p>
86 * @param xml 配置文件的內容
87 * @param type 郵件類型
88 */
89 private void parseXML(String xml, String type) {
90 type=type.toLowerCase();//忽略type字段的大小寫
91 try {
92 // 解析XML,獲得doc對象
93 Document doc = DocumentHelper.parseText(xml);
94
95 // 判斷type的值是否正確,type的值應是報文二級節點中的一個
96 String flag = doc.getRootElement().element(type) + "";
97 if (null == flag || flag.equals("null"))
98 throw new DocumentException(
99 "傳入的type值不對,type的值應是SendMail.xml報文中二級節點的一個,請查看文件然后重新傳入type的值");
100
101 // 設置主機名稱
102 Element hostEle = (Element) doc.selectSingleNode("/mail/" + type
103 + "/host");
104 if (null == hostEle || "".equals(hostEle.getTextTrim())) {
105 throw new DocumentException("郵件服務器域名或IP不能為空,請檢查配置文件SendMail.xml");
106 }
107 mailInfo.setHost(hostEle == null ? "" : hostEle.getTextTrim());
108
109 // 設置發件人
110 Element fromEle = (Element) doc.selectSingleNode("/mail/" + type
111 + "/from");
112 if (null == fromEle || "".equals(fromEle.getTextTrim())) {
113 throw new DocumentException("發件人地址不能為空,請檢查配置文件SendMail.xml");
114 }
115 mailInfo.setFrom(fromEle == null ? "" : fromEle.getTextTrim());
116
117 // 設置郵件主題
118 Element titleEle = (Element) doc.selectSingleNode("/mail/" + type
119 + "/title");
120 mailInfo.setTitle(titleEle == null ? "" : titleEle.getTextTrim());
121
122 // 設置收件人,對多個收件人的處理放在后面
123 Element toEle = (Element) doc.selectSingleNode("/mail/" + type
124 + "/to");
125 if (null == toEle || "".equals(toEle.getTextTrim())) {
126 throw new DocumentException("收件人地址不能為空,請檢查配置文件SendMail.xml");
127 }
128 mailInfo.setTo(toEle == null ? "" : toEle.getTextTrim());
129
130 // 設置抄送,對多個抄送人的處理放在后面
131 Element ccEle = (Element) doc.selectSingleNode("/mail/" + type
132 + "/cc");
133 mailInfo.setCc(ccEle == null ? "" : ccEle.getTextTrim());
134
135 //設置發件人用戶名
136 Element nameEle = (Element) doc.selectSingleNode("/mail/" + type
137 + "/username");
138 if(null==nameEle||"".equals(nameEle.getTextTrim())){
139 throw new DocumentException("發件人用戶名不能為空,請檢查配置文件SendMail.xml");
140 }
141 mailInfo.setUsername(nameEle == null ? "" : nameEle.getTextTrim());
142
143 //設置發件人密碼
144 Element passEle = (Element) doc.selectSingleNode("/mail/" + type
145 + "/password");
146 if(null==passEle||"".equals(passEle.getTextTrim())){
147 throw new DocumentException("發件人密碼不能為空,請檢查配置文件SendMail.xml");
148 }
149 mailInfo.setPassword(passEle == null ? "" : passEle.getTextTrim());
150
151 } catch (DocumentException e) {
152 e.printStackTrace();
153 }
154 }
155
156 /**
157 * <p>Title: sendMailOfValidate</p>
158 * <p>Description:發送郵件的方法,Authenticator類驗證</p>
159 */
160 private void sendMailOfValidate() {
161 Properties props = System.getProperties();
162 props.put("mail.smtp.host", mailInfo.getHost());//設置郵件服務器的域名或IP
163 props.put("mail.smtp.auth", "true");//授權郵件,mail.smtp.auth必須設置為true
164
165 String password=mailInfo.getPassword();//密碼
166 try {
167 password=Encrypt.DoDecrypt(password);//如果密碼經過加密用此方法對密碼進行解密
168 } catch (NumberFormatException e1) {
169 //如果密碼未經過加密,則對密碼不做任何處理
170 }
171 //傳入發件人的用戶名和密碼,構造MyAuthenticator對象
172 MyAuthenticator myauth = new MyAuthenticator(mailInfo.getUsername(),password);
173
174 //傳入props、myauth對象,構造郵件授權的session對象
175 Session session = Session.getDefaultInstance(props, myauth);
176
177 //將Session對象作為MimeMessage構造方法的參數傳入構造message對象
178 MimeMessage message = new MimeMessage(session);
179 try {
180 message.setFrom(new InternetAddress(mailInfo.getFrom()));//發件人
181
182 // 對多個收件人的情況進行處理,配置文件SendMail.xml中每個收件人之間必須用逗號隔開的
183 if (mailInfo.getTo() != null && !"".equals(mailInfo.getTo())) {
184 String to[] = mailInfo.getTo().split(",");
185 for (int i = 0; i < to.length; i++) {
186 message.addRecipient(Message.RecipientType.TO,
187 new InternetAddress(to[i]));// 收件人
188 }
189 }
190
191 // 對多個抄送人的情況進行處理,每個抄送人之間用逗號隔開的
192 if (mailInfo.getCc() != null && !"".equals(mailInfo.getCc())) {
193 String cc[] = mailInfo.getCc().split(",");
194 for (int j = 0; j < cc.length; j++) {
195 message.addRecipient(Message.RecipientType.CC,
196 new InternetAddress(cc[j]));// 抄送
197 }
198 }
199 message.setSubject(mailInfo.getTitle());// 主題
200
201 message.setText(mailInfo.getContent());// 內容
202
203 Transport.send(message);// 調用發送郵件的方法
204
205 log.debug("郵件發送成功");
206 } catch (AddressException e) {
207 e.printStackTrace();
208 } catch (MessagingException e) {
209 e.printStackTrace();
210 }
211 }
212
213 /**
214 * <p>Title: sendMail</p>
215 * <p>Description:外部程序調用的入口</p>
216 * @param type 郵件的類型,目前有三種,即logmessage、checkmessage、ordermessage,type只能傳這三個值中一個,傳其他的任何值都不行
217 * @param content 郵件的內容
218 * @throws Exception
219 */
220 public void sendMail(String type,String content) throws Exception{
221 log.debug("入參type="+type);
222 log.debug("入參content="+content);
223 if (null == type || "".equals(type) || null == content
224 || "".equals(content)) {
225 throw new Exception("方法的入參type和content字段的值都不能為空或null");
226 }
227
228 String xml=readXML(XML_PATH);//獲得xml字符串
229
230 parseXML(xml,type);//解析xml字符串,把對應字段的值放入到mailInfo對象中
231
232 mailInfo.setContent(content);//設置發送的內容
233
234 sendMailOfValidate();//發送郵件
235
236 }
237
238 /**
239 * 為了方便直接用main方法測試
240 * @param args
241 * @throws Exception
242 */
243 public static void main(String args[]) throws Exception {
244
245 SendMail mail = new SendMail();
246
247 // type類型,根據此字段去配置文件SendMail.xml中匹配,然后發到相應的郵箱
248 String type = "logmessage";
249
250 // 郵件的內容,實際開發中這個內容是前台傳到后台
251 String content = "你好,歡飲使用JavaMail包開發郵件功能";
252
253 // 在其他類中調用時只能看到sendMail方法,為了保護內部細節,其它的方法都聲明為私有的
254 mail.sendMail(type, content);
255 //這個項目中沒有日志文件,所以我打印一句話來告訴自己程序已經成功運行
256 System.out.println("****success****");
257
258 }
259 }
說明:代碼中的校驗可能不太嚴謹和全面,因為這個配置文件是由開發人員自己配置,並且對配置文件也有詳細的介紹,所以代碼中就省略去了許多的校驗。
SendMail.xml 郵件配置文件

1 <?xml version="1.0" encoding="UTF-8"?><!-- 此處編碼格式必須用UTF-8格式,這樣和程序中的解碼是統一的,不會出現亂碼 -->
2 <mail>
3 <logmessage><!--報文的二級節點,為了使傳入的type值對大小寫不限制,故此處必須用小寫 -->
4 <host>smtp.qq.com</host><!-- 郵件服務器域名或IP,必填項 -->
5 <from>838045782@qq.com</from><!-- 發件人 ,必填項 -->
6 <to>838045782@qq.com,taipeng0820@163.com</to><!-- 收件人,多個收件人之間用英文狀態下的逗號隔開,必填項 -->
7 <cc>838045782@qq.com</cc><!-- 抄送,多個抄送人之間用英文狀態下的逗號隔開-->
8 <title>test JavaMail</title><!-- 郵件主題-->
9 <username>838045782@qq.com</username><!-- 發件人郵箱的用戶名,即email的全地址,必填項 -->
10 <password>123456</password><!-- 發件人郵箱的密碼,像QQ郵箱如果設置了獨立密碼應輸入獨立密碼,必填項,為了安全起見填寫密碼之前最好用Encrypt類的DoEncrypt方法加密 -->
11 </logmessage>
12
13 <checkmessage>
14 <host></host>
15 <from></from>
16 <to></to>
17 <cc></cc>
18 <title></title>
19 <username></username>
20 <password></password>
21 </checkmessage>
22
23 <ordermessage>
24 <host></host>
25 <from></from>
26 <to></to>
27 <cc></cc>
28 <title></title>
29 <username></username>
30 <password></password>
31 </ordermessage>
32 </mail>
注意:密碼是必填項,由於是介紹,我把自己的密碼給刪掉換成了123456,實際中需根據需要配置郵件服務器域名、發件人、收件人、抄送人、用戶名和密碼。
result
運行方式:執行運行SendMail.java類中的main方式就可以測試了,測試之前請按說明配置xml文件。
首次運行你可能會遇到以下的錯誤,所以note.txt文件就用來提供遇到的錯誤以及對應的解決方案
note.txt
java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream
at javax.mail.Session.loadProvidersFromStream(Session.java:928)
at javax.mail.Session.access$000(Session.java:174)
at javax.mail.Session$1.load(Session.java:870)
at javax.mail.Session.loadResource(Session.java:1084)
at javax.mail.Session.loadProviders(Session.java:889)
at javax.mail.Session.<init>(Session.java:210)
at javax.mail.Session.getDefaultInstance(Session.java:299)
at mail.SendMail.sendMail(SendMail.java:31)
at mail.SendMail.main(SendMail.java:50)
Exception in thread "main"
解決方案:在myeclipse的安裝目錄下搜索javaee.jar,然后用壓縮軟件打開,刪除javax下的mail文件夾
java.lang.NoClassDefFoundError: com/sun/activation/registries/LogSupport
at javax.activation.MailcapCommandMap.<init>(MailcapCommandMap.java:140)
at javax.activation.CommandMap.getDefaultCommandMap(CommandMap.java:61)
at javax.activation.DataHandler.getCommandMap(DataHandler.java:153)
at javax.activation.DataHandler.getDataContentHandler(DataHandler.java:611)
at javax.activation.DataHandler.writeTo(DataHandler.java:315)
at javax.mail.internet.MimeUtility.getEncoding(MimeUtility.java:264)
at javax.mail.internet.MimeBodyPart.updateHeaders(MimeBodyPart.java:1299)
at javax.mail.internet.MimeMessage.updateHeaders(MimeMessage.java:2071)
at javax.mail.internet.MimeMessage.saveChanges(MimeMessage.java:2039)
at javax.mail.Transport.send(Transport.java:119)
at mail.SendMail.sendMailNoValidate(SendMail.java:48)
at mail.SendMail.main(SendMail.java:96)
Exception in thread "main"
解決方案:在myeclipse的安裝目錄下搜索javaee.jar,然后用壓縮軟件打開,刪除javax文件夾下的activation文件夾
javax.mail.SendFailedException: Sending failed;
nested exception is:
javax.mail.MessagingException: 503 Error: need EHLO and AUTH first !
at javax.mail.Transport.send0(Transport.java:219)
at javax.mail.Transport.send(Transport.java:81)
at com.asiainfo.bboss.sendmail.SendMailServiceImpl.sendMailNoValidate(SendMailServiceImpl.java:210)
at com.asiainfo.bboss.sendmail.SendMailServiceImpl.sendMail(SendMailServiceImpl.java:243)
at com.asiainfo.bboss.sendmail.SendMailServiceImpl.main(SendMailServiceImpl.java:261)
解決方案:props.put("mail.smtp.auth", "true");
javax.mail.SendFailedException: Sending failed;
nested exception is:
javax.mail.AuthenticationFailedException
at javax.mail.Transport.send0(Transport.java:219)
at javax.mail.Transport.send(Transport.java:81)
at com.asiainfo.bboss.sendmail.SendMailServiceImpl.sendMailNoValidate(SendMailServiceImpl.java:211)
at com.asiainfo.bboss.sendmail.SendMailServiceImpl.sendMail(SendMailServiceImpl.java:244)
at com.asiainfo.bboss.sendmail.SendMailServiceImpl.main(SendMailServiceImpl.java:262)
解決方案: MyAuthenticator myauth = new MyAuthenticator(mailInfo.getUsername(),password);
運行截圖如下:
圖1:myeclipse后台打印的結果 此項目下沒有log4j.properties文件,故會有紅色的信息,代碼中的log也沒有打印出來
圖2:去我的QQ郵箱收信---收件箱列表
圖3:去我的QQ郵箱收信---郵件內容
圖4:去我的163郵箱收信---收件箱列表
確認已經收到郵件,因為163郵件顯示的是本人的真實姓名,這里就不截圖了。
圖5:去我的163郵箱收信---郵件內容
確認已經收到郵件,因為163郵件顯示的是本人的真實姓名,這里就不截圖了。
以上只是對javamail插件一個小小的應用,此插件也可以做收信、轉發、答復、上傳附件等功能,
希望更多的朋友可以接觸到javamail插件,權當做一次宣傳了。