Java, Only Java!

          統計

          留言簿(20)

          積分與排名

          好友空間

          文檔技巧

          閱讀排行榜

          評論排行榜

          Apusic上用JavaMail發郵件

          Apusic上用JavaMail發郵件
          0. JavaMail基本介紹
          ?JavaMail是屬于J2EE框架中的一部分,主要是為簡化Mail部分開發工作。使用JavaMail發送郵件需要以下步驟:
          ?1)初始化Session實例;
          ?在初始化Session實例中有兩種方式:使用JNDI初始化和在代碼中自行完成初始化。
          ?★ 如果SMTP不需要認證,則不再做其他工作;
          ?★ 如果SMTP需要認證,則確定在Session中提供嵌入認證信息,還是由3)Transport完成認證過程。
          ?2)初始化Message實例,填充相關信息;
          ?3)初始化Transport實例,連接到遠程SMTP服務器,發送郵件。
          ?在初始化Transport實例時也有兩種情況:
          ?★ 如果SMTP不需要認證,可以直接調用send()函數發送郵件,應用服務器會在后臺調用connect()函數完成誰,進行郵件發送;
          ?★ 如果SMTP需要認證,需要調用connect()函數,并提供認證需要的用戶名/密碼,才可以正確發送郵件。
          ?
          1. javax.mail.Session的初始化
          1.1. 使用JNDI初始化(配置JavaMail的JNDI)
          在Apusic的J2EE應用中找到apusic-application.xml文件,增加<mail-session>部分,示例如下:
          <apusic-application>
          ?<module uri="web.war">
          ??<web />
          ?</module>
          ?<mail-session>
          ??<jndi-name>javamail/myMail</jndi-name>
          ??<property name="mail.transport.protocol" value="smtp" />
          ??<property name="mail.smtp.host" value="smtp.163.com" />
          ??<property name="mail.smtp.user" value="user" />
          ??<property name="mail.smtp.password" value="password" />
          ??<property name="mail.smtp.auth" value="true" />
          ??<property name="mail.from" value="user@163.com" />
          ?</mail-session>
          </apusic-application>

          1.1.1. 通過JNDI找到JavaMail
          1.1.1.1. 使用遠程訪問獲得JavaMail
          ?Hashtable env=new Hashtable();
          ?env.put(Context.INITIAL_CONTEXT_FACTORY,"com.apusic.naming.jndi.CNContextFactory");
          ?env.put(Context.PROVIDER_URL,"iiop://localhost:6888");
          ?//插入相關驗證信息
          ?env.put(Context.SECURITY_CREDENTIALS,"admin" ) ;
          ?env.put(Context.SECURITY_PRINCIPAL,"admin");
          ?Context initCtx=new InitialContext(env);
          ?System.out.println(initCtx.PROVIDER_URL);
          ?//通過RMI 取得
          ?Session myMailSession = (Session) initCtx.lookup("javamail/myMailNoAuth");
          1.1.1.2. 使用Apusic默認方式獲得JavaMail
          ?Context initCtx = new InitialContext();
          ?Session myMailSession = (Session) initCtx.lookup("javamail/myMailNoAuth");
          ?System.out.println(myMailSession.getProperty("mail.smtp.host"));
          ?
          1.1.2. 通過資源注入配置JavaMail
          ?@Resource(mappedName = "javamail/myMailAuth", type = javax.mail.Session.class, shareable = true, authenticationType = Resource.AuthenticationType.CONTAINER, description = "my email with auth")
          ?private Session myAuthMailSession;
          或者
          ?@Resource(mappedName = "javamail/myMailAuth")
          ?private Session myAuthMailSession;

          1.2. 在代碼中初始化
          1.2.1. 無須認證的初始化
          ?final Properties props = new Properties();
          ?props.put("mail.transport.protocol", "smtp");
          ?props.put("mail.smtp.auth", "false");
          ?props.put("mail.smtp.host", "localhost");
          ?Session myMailSession = Session.getInstance(props);
          1.2.2. 需要認證的初始化(Session實例構造時提供認證支持)
          ?final Properties props = new Properties();
          ?props.put("mail.transport.protocol", "smtp");
          ?props.put("mail.smtp.auth", "true");
          ?props.put("mail.smtp.host", "smtp.163.com");
          ?Session myMailSession = Session.getInstance(props, new Authenticator() {
          ??public PasswordAuthentication getPasswordAuthentication() {
          ???return new PasswordAuthentication("user", "password");}?});
          1.2.3. 需要認證的初始化(Session配置參數提供認證支持)
          ?myMailSession.setPasswordAuthentication(
          ??new URLName(props.getProperty("mail.transport.protocol")+"://"+??
          ???????????????? props.getProperty("mail.smtp.user")+"@"+??
          ???????????????? props.getProperty("mail.smtp.host")),??
          ??????? new PasswordAuthentication(props.getProperty("mail.smtp.user"),??
          ???????????????? props.getProperty("mail.smtp.password")));??

          1.2.4. 需要認證的初始化(Transport配置參數提供認證支持)
          ??// 發送郵件
          ??javax.mail.Transport myTransport = myMailSession.getTransport("smtp");
          ??myTransport.connect("smtp.163.com", "user", "password");
          ??myTransport.sendMessage(msg, msg.getRecipients(Message.RecipientType.TO));
          ??myTransport.close();
          ???
          1.4. 對Session調試的配置
          ●?可以在mail-session中加入<property name="mail.debug" value="true" />
          ●?可以在Session初始化前加入props.put("mail.debug", "true");
          ●?可以在Session初始化后,通過代碼控制myMailSession.setDebug(true);

          1.5. Properties的解釋
          ◆?mail.store.protocol:用于檢索郵件的協議
          ◆?mail.transport.protocol:用于傳送郵件的協議
          ◆?mail.host:默認的主機名,默認是本地計算機。
          ◆?mail.user:默認的用戶名。
          ◆?mail.from:默認的返回地址。
          ◆?mail.debug:是否輸出DEBUG信息。默認為False。
          ◆?mail.protocol.host:指定協議的主機名,沒有指定就用mail.host。例如:mail.smtp.host=smtp.163.com
          ◆?mail.protocol.user:指定協議的用戶名,沒有指定就用mail.user。例如:mail.smtp.user=user
          ◆?mail.protocol.from:指定協議的返回地址,沒有指定就用mail.from。例如:mail.smtp.from=user@163.com
          ◆?mail.smtp.auth:如果是True,就會登錄SMTP服務器,獲得授權才能發送郵件。默認為False。


          2. 通過JavaMail發送郵件
          2.1. 通過無須認證的SMTP發郵件
          ??final Properties props = new Properties();
          ??props.put("mail.transport.protocol", "smtp");
          ??props.put("mail.smtp.auth", "false");
          ??props.put("mail.smtp.host", "localhost");
          ??try {
          ???Session myMailSession = Session.getInstance(props);
          ???myMailSession.setDebug(true); // 打開DEBUG模式
          ???Message msg = new MimeMessage(myMailSession);
          ???msg.setFrom(new InternetAddress("user@163.com"));
          ???msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("zhuyuanxiang@apusic.com"));
          ???msg.setContent("I have a email test!", "text/plain");
          ???msg.setSentDate(new java.util.Date());
          ???msg.setSubject("Test");
          ???msg.setText("This is a test!\n");
          ???System.out.println("1.Please wait for sending one...");

          ???// 發送郵件
          ???// javax.mail.Transport.send(msg); // 與下面四行的功能一樣
          ???javax.mail.Transport myTransport = myMailSession.getTransport("smtp");
          ???myTransport.connect();
          ???myTransport.sendMessage(msg, msg.getRecipients(Message.RecipientType.TO));
          ???myTransport.close();
          ???
          ???System.out.println("2.Your message had send!");
          ??} catch (Exception error) {
          ???System.out.println("*.I am sorry to tell you the fail for " + error);
          ??}

          注:測試可以使用Microsft IIS SMTP 服務,安裝好啟動服務后,還需要進入“IIS管理器”,增加一個“遠程域”,對于“遠程域”的“出站安全性”需要把用戶名和密碼加上(就是平時發郵件時登錄用的用戶名/密碼),否則郵件發不出去。

          2.2. 通過需要認證的SMTP發郵件
          2.2.1. 需要認證的初始化(Session實例構造時提供認證支持)
          ?final Properties props = new Properties();
          ?props.put("mail.transport.protocol", "smtp");
          ?props.put("mail.smtp.auth", "true");
          ?props.put("mail.smtp.host", "smtp.163.com");

          ?try {
          ??Session myMailSession = Session.getInstance(props, new Authenticator() {
          ???public PasswordAuthentication getPasswordAuthentication() {
          ????return new PasswordAuthentication("user", "password");
          ???}
          ??});
          ??myMailSession.setDebug(true);?// 打開DEBUG模式
          ??InternetAddress address = new InternetAddress("user@163.com");
          ??String message = "I have a email test!";
          ??Message msg = new MimeMessage(myMailSession);
          ??msg.setFrom(address);
          ??msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("zhuyuanxiang@apusic.com"));
          ??msg.setContent(message, "text/plain");
          ??msg.setSentDate(new java.util.Date());
          ??msg.setSubject("Test");
          ??msg.setText("This is a test!\n");
          ??out.println("1.Please wait for sending...");
          ??
          ??// 發送郵件
          ??javax.mail.Transport myTransport = myMailSession.getTransport("smtp");
          ??myTransport.connect();
          ??myTransport.sendMessage(msg, msg.getRecipients(Message.RecipientType.TO));
          ??myTransport.close();
          ??// javax.mail.Transport.send(msg);?// 注釋上四行,打開這行代碼,功能一樣
          ??out.println("2.Your message had send!");
          ?} catch (Exception error) {
          ??out.println("*.I am sorry to tell you the fail for " + error);
          ?}

          2.2.2. 需要認證的初始化(Session配置參數提供認證支持)
          ?final Properties props = new Properties();
          ?props.put("mail.transport.protocol", "smtp");
          ?props.put("mail.smtp.auth", "true");
          ?props.put("mail.smtp.host", "smtp.163.com");

          ?try {
          ??Session myMailSession = Session.getInstance(props);
          ??myMailSession.setDebug(true);?// 打開DEBUG模式
          ??myAuthMailSession.setPasswordAuthentication(
          ???new URLName("smtp://user@host", new PasswordAuthentication("user","password"));?
          ??InternetAddress address = new InternetAddress("user@163.com");
          ??String message = "I have a email test!";
          ??Message msg = new MimeMessage(myMailSession);
          ??msg.setFrom(address);
          ??msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("zhuyuanxiang@apusic.com"));
          ??msg.setContent(message, "text/plain");
          ??msg.setSentDate(new java.util.Date());
          ??msg.setSubject("Test");
          ??msg.setText("This is a test!\n");
          ??out.println("1.Please wait for sending...");
          ??
          ??// 發送郵件
          ??javax.mail.Transport myTransport = myMailSession.getTransport("smtp");
          ??myTransport.connect();
          ??myTransport.sendMessage(msg, msg.getRecipients(Message.RecipientType.TO));
          ??myTransport.close();
          ??// javax.mail.Transport.send(msg);?// 注釋上四行,打開這行代碼,功能一樣
          ??out.println("2.Your message had send!");
          ?} catch (Exception error) {
          ??out.println("*.I am sorry to tell you the fail for " + error);
          ?}

          2.2.3. 需要認證的初始化(Transport配置參數提供認證支持)
          ??final Properties props = new Properties();
          ??props.put("mail.transport.protocol", "smtp");
          ??props.put("mail.smtp.auth", "true");

          ??try {
          ???Session myMailSession = Session.getInstance(props);
          ???myMailSession.setDebug(true); // 打開DEBUG模式
          ???Message msg = new MimeMessage(myMailSession);
          ???msg.setFrom(new InternetAddress("user@163.com"));
          ???msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse("zhuyuanxiang@apusic.com"));
          ???msg.setContent("I have a email test!", "text/plain");
          ???msg.setSentDate(new java.util.Date());
          ???msg.setSubject("Test");
          ???msg.setText("This is a test!\n");
          ???System.out.println("1.Please wait for sending two...");

          ???// 發送郵件
          ???javax.mail.Transport myTransport = myMailSession.getTransport("smtp");
          ???myTransport.connect("smtp.163.com", "user", "password");
          ???myTransport.sendMessage(msg, msg.getRecipients(Message.RecipientType.TO));
          ???myTransport.close();
          ???// javax.mail.Transport.send(msg); // 這行不能使用。
          ???System.out.println("2.Your message had send!");
          ??} catch (Exception error) {
          ???System.out.println("*.I am sorry to tell you the fail for " + error);
          ??}
          ?}

          注:資源注入的Session發送郵件時:
          無須認證的SMTP,可以參考2.1.
          需要認證的SMTP,可以參考2.2.1.

          參考:
          http://java.sun.com/products/javamail/javadocs/com/sun/mail/smtp/package-summary.html
          http://commons.apache.org/email/userguide.html
          http://www.aygfsteel.com/Unmi/archive/2007/06/07/124179.html
          http://unmi.blogcn.com/diary,117630488.shtml


          Apusic Stduio打包的示例工程。
          http://zhuyuanxiang.javaeye.com/topics/download/d6f5c3a9-9cd9-30be-9b64-9e311900b304

          備注:本文耗時1周完成。

          posted on 2008-09-04 12:11 zYx.Tom 閱讀(1654) 評論(7)  編輯  收藏 所屬分類: 1.Java世界

          評論

          # re: Apusic上用JavaMail發郵件 2008-09-04 12:34 隔葉黃鶯

          說真的,Apusic 用處理 JavaMail 資源還稍欠了些,理想的狀態應該是代碼只要寫成如下:

          Session myMailSession = (Session)ctx.lookup("mail/mailSession");
          Message msg = new MimeMessage(myMailSession);
          ......
          Transport.send(msg);

          然后要不要驗證,由配置屬性 mail.smtp.auth 來自行決定,Spring 是做到了這一點的。

          要是像上面那樣,代碼基本完成了全過程,看是用不著在 Apusic 進行相關的配置的。我覺得這一點上 Apusic 應該要有所改進。  回復  更多評論   

          # re: Apusic上用JavaMail發郵件 2008-09-04 12:48 朱遠翔-Apusic技術顧問

          @隔葉黃鶯
          Apusic也是這樣處理的呀?
          而且是否認證其實跟Apusic無關,這個是Sun提供的JavaMail包里面決定的。
          個人感覺發送時登錄過程,無論哪個應用服務器都需要按照上面的代碼操作吧。
          我對Spring的JavaMail了解不多,是否方便給出完整的代碼進行討論,謝謝。
            回復  更多評論   

          # re: Apusic上用JavaMail發郵件 2008-09-04 14:19 隔葉黃鶯

          WAS5.1也是要自己登錄,而且用戶名和密碼必須以額外的屬性進行設置,然后在程序中取出來,所以我沒去用 WAS 的 MailSession 資源配置。或是自己程序處理。
          或是用 Spring 的配置,就比較輕松,Spring 會自己完成登錄過程。

          我之前寫過一個 《JavaMail 發郵件需要 SMTP 驗證的三種處理方式》(http://www.aygfsteel.com/Unmi/archive/2007/06/07/124179.html)時看過 Jakarta-commons-email(如 SimpleEmail 類) 包和 Spring 的 MailSender(如JavaMailSenderImple) 能夠自動幫你完成驗證過程。

          關于 Jakarta-commons-email 自動完成驗證發送郵件我之前也寫過一篇,不過這里就不提了。列出如果要 Spring 自動完成驗證時的 bean 配置如下:

          <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
          <property name="host" value="${mail.host}"/>
          <property name="username" value="${mail.username}"/>
          <property name="password" value="${mail.password}"/>
          <property name="javaMailProperties">
          <props>
          <prop key="mail.smtp.auth">true</prop>
          <prop key="mail.smtp.timeout">25000</prop>
          </props>
          </property>
          </bean>

          關鍵是這個 mail.smtp.auth 設置為 true,然后在代碼中取到 mailSender 實例就能直接發送郵件,Spring 自動取到配置中的用戶名和密碼幫你登錄驗證,它采用的方法是:

          Transport transport = mailSession.getTransport();
          transport.connect(props.getProperty("mail.smtp.host"), props
          .getProperty("mail.smtp.user"), props
          .getProperty("mail.smtp.password"));

          不好意思,占用了你太多的頁面資源,僅供參考。  回復  更多評論   

          # re: Apusic上用JavaMail發郵件 2008-09-04 17:17 朱遠翔-Apusic技術顧問

          @隔葉黃鶯
          非常感謝你的回復,我又去深入了解了一下JavaMail的實現,分析認為只要是通過J2EE標準的應用服務器(Websphere、Weblogic、Apusic)應該都按照上文或你寫的《三種方式》來操作才能正確發送需要SMTP認證的郵件,而上文的目的就是想說清楚如何發送的機制。
          但是,如果在代碼中涉及太多與業務無關的對應用系統設計和開發都不夠友好,因此,如果使用Spring可以利用Spring+JNDI來操作,如果不用Spring那可以使用Commons-email+JNDI來簡化Email操作過程。
          最后,非常感謝你對本文的關注,你的探討也讓我又有新的收獲,希望有機會多多交流。

          另:三種方式中第二種我沒有驗證成功,我反編譯過源代碼,也看過JavaMail提供的規范說明,個人覺得是不行的。如果你能夠成功運行,請告訴我,謝謝。
          第一種方法重載了Authenticator()類,Transport調用connect()函數時,會取得需要的用戶名/密碼。
          第三種方法直接將用戶名/密碼傳給Transport,而且傳送使用的是sendMessage()函數,因此也能夠成功。  回復  更多評論   

          # re: Apusic上用JavaMail發郵件 2008-09-08 11:05 隔葉黃鶯

          謝謝你的提醒,原文的第二種方法確實有些問題,現已改正了,其實就是 URLName 要的參數形式是:smpt://user@mail.smtp.host

          具體代碼還是詳見那篇日志。

          的確,像 J2EE 標準應用服務器中配置了 MailSession,資源都是需要自己手工進行驗證,而只有 Spring 簡化的 Email 操作,不知為何。所以我基本不用應用服務器的 MailSession 資源。

          其實我覺得應用服務器可以做得靈活一些,例如通過設置不同的屬性來決定驗證方式,因為有些轉發協議是 smtps,驗證方面我認為是與具體業務無關的,應該可由應用服務器來承擔。  回復  更多評論   

          # re: Apusic上用JavaMail發郵件 2008-09-16 10:11 朱遠翔-Apusic技術顧問

          @隔葉黃鶯
          從功能上說,由應用服務器完成驗證更加合理,但是這樣的操作會帶來移植的問題,因為如果開發期采用了應用服務器提供的模式,那么移植到其他應用服務器時就會需要個性代碼。
          其實,這塊的功能直接用Jakarta-commons-email就可以了,或者像Spring、Struts等框架自行提供,因為攜帶這些框架就不會給應用移植帶來麻煩了。  回復  更多評論   

          # re: Apusic上用JavaMail發郵件 2008-09-16 10:46 朱遠翔-Apusic技術顧問

          2008-09-16
          我對文章進行了修改,受到“隔葉黃鶯”文章的啟發,現在已經將Session配置參數進行認證的方式加入其中。
          另:Apusic Studio工程沒有更新,如果自己修改代碼測試Session配置參數進行認證失敗,可以在此繼續交流。
          對“隔葉黃鶯”提供的無私幫助在此表示感謝。  回復  更多評論   

          主站蜘蛛池模板: 宜宾市| 光泽县| 温泉县| 阿勒泰市| 龙岩市| 广安市| 汉沽区| 乌拉特后旗| 南华县| 盐山县| 仪征市| 桂东县| 潼南县| 额济纳旗| 鹤山市| 六盘水市| 洛南县| 广安市| 眉山市| 山东省| 漠河县| 张家口市| 宝应县| 宽甸| 江永县| 右玉县| 静海县| 石首市| 永修县| 临夏县| 鄂州市| 奎屯市| 嘉祥县| 西安市| 广德县| 稻城县| 嵩明县| 改则县| 涿州市| 醴陵市| 山丹县|