2012年9月4日 星期二

[ Java 代碼範本 ] 透過 Yahoo Mail account 使用 JavaMail 送信

Preface : 
最近需要寫一個 watch dog 來定時檢視我們提供的 service 是否還活著, 由於需要再 service break 發 mail 通知相關人等, 故拜了 Google 大神將實作細節整理在這. 
這邊使用 Yahoo SMTP/POP 作為 mail sending 的平台, 因此你需要有對應的 Yahoo Mail account; 另外使用的 Java 套件是 JavaMail, 你需要將它加到你專案的 classpath 中. 

Mail account 設定 : 
在開使撰寫代碼前, 先要設定你的 Mail Account. 請進入你的 Mail account 後, 在左上方按照下面指示進入設定頁面 : 
 

接著按照下面說明完成設定 : 
 

範例代碼 : 
接著我建立的一個類別 MailAgent 方便後續使用, 完整代碼如下 : 
- MailAgent.java : 
  1. package test;  
  2.   
  3. import java.util.LinkedList;  
  4. import java.util.List;  
  5. import java.util.Properties;  
  6.   
  7. import javax.mail.Authenticator;  
  8. import javax.mail.Message;  
  9. import javax.mail.PasswordAuthentication;  
  10. import javax.mail.Session;  
  11. import javax.mail.Store;  
  12. import javax.mail.Transport;  
  13. import javax.mail.internet.InternetAddress;  
  14. import javax.mail.internet.MimeMessage;  
  15.   
  16. import org.apache.commons.codec.binary.Base64;  
  17.   
  18. public class MailAgent {  
  19.     private String          username = "";  // Your account in Yahoo  
  20.     private String          password = "";  // Your password of account in Yahoo  
  21.     private String          smtpHost = "smtp.mail.yahoo.com";  
  22.     private String          popHost = "pop.mail.yahoo.com";  
  23.     private String          fromAddress = "";  
  24.     private List  toAddressList = null;  
  25.     private Properties      props = null;  
  26.     public boolean          isDebug = false;  
  27.   
  28.     public MailAgent(){}  
  29.     public MailAgent(String user,String pwd, String smtpHost, String popHost)  
  30.     {  
  31.         this.username = user;   
  32.         this.password = pwd;  
  33.         this.smtpHost = smtpHost;  
  34.         this.popHost = popHost;  
  35.     }  
  36.       
  37.     public void resetProp()  
  38.     {  
  39.         props = System.getProperties();       
  40.         props.put("mail.smtp.host", smtpHost);  
  41.         //props.put("mail.from",from);  
  42.         props.put("mail.smtp.starttls.enable""true");  
  43.         props.put("mail.smtp.auth""true");  
  44.         props.put("mail.debug", String.valueOf(isDebug));  
  45.     }  
  46.       
  47.     public String getUsername() {  
  48.         return username;  
  49.     }  
  50.     public void setUsername(String username) {  
  51.         this.username = username;  
  52.     }  
  53.     public String getPassword() {  
  54.         return password;  
  55.     }  
  56.     public void setPassword(String password)   
  57.     {  
  58.         this.password = password;  
  59.     }  
  60.     public void setPasswordInBase64(String passwordInBase64)  
  61.     {  
  62.         Base64 base64 = new Base64();  
  63.         this.password = new String(base64.decode(passwordInBase64.getBytes()));  
  64.     }  
  65.       
  66.     public List getToAddressList() {  
  67.         return toAddressList;  
  68.     }  
  69.     public void setToAddressList(List toAddressList) {  
  70.         this.toAddressList = toAddressList;  
  71.     }  
  72.     public String getSmtpHost() {  
  73.         return smtpHost;  
  74.     }  
  75.     public void setSmtpHost(String smtpHost) {  
  76.         this.smtpHost = smtpHost;  
  77.     }  
  78.     public String getPopHost() {  
  79.         return popHost;  
  80.     }  
  81.     public void setPopHost(String popHost) {  
  82.         this.popHost = popHost;  
  83.     }  
  84.       
  85.     public String getFromAddress() {  
  86.         return fromAddress;  
  87.     }  
  88.     public void setFromAddress(String fromAddress) {  
  89.         this.fromAddress = fromAddress;  
  90.     }  
  91.     public boolean isDebug() {  
  92.         return isDebug;  
  93.     }  
  94.     public void setDebug(boolean isDebug) {  
  95.         this.isDebug = isDebug;  
  96.     }  
  97.     public boolean sendMail(List toAddressList, String subject, String body)  
  98.     {  
  99.         try  
  100.         {  
  101.             if(props==null) resetProp();  
  102.             // Get session  
  103.             Session session = Session.getDefaultInstance(props, new Authenticator() {  
  104.                 @Override  
  105.                 protected PasswordAuthentication getPasswordAuthentication() {  
  106.                     return new PasswordAuthentication(username, password);  
  107.                 }  
  108.             });  
  109.             session.setDebug(isDebug);  
  110.             // Pop Authenticate yourself  
  111.             Store store = session.getStore("pop3");  
  112.             store.connect(popHost, username, password);  
  113.               
  114.             MimeMessage message = new MimeMessage(session);  
  115.             message.setFrom(new InternetAddress(fromAddress));  
  116.             message.setSubject(subject);  
  117.             message.setText(body);        
  118.             for(String to:toAddressList)  
  119.             {                                 
  120.                 message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));                                         
  121.             }     
  122.             // Send message  
  123.             Transport.send(message);  
  124.             return true;  
  125.         }  
  126.         catch(Exception e)  
  127.         {  
  128.             e.printStackTrace();  
  129.         }  
  130.         return false;  
  131.     }  
  132.       
  133.     public boolean sendMail(String toAddress, String subject, String body)  
  134.     {  
  135.         List toAddressList = new LinkedList();  
  136.         toAddressList.add(toAddress);  
  137.         return this.sendMail(toAddressList, subject, body);  
  138.     }  
  139.       
  140.     public boolean sendMail(String subject, String body)  
  141.     {  
  142.         if(toAddressList==null || fromAddress==null || fromAddress.trim().isEmpty()) return false;  
  143.         else  
  144.         {  
  145.             return sendMail(toAddressList, subject, body);  
  146.         }  
  147.     }  
  148. }  
接著你只要創建這個類別的物件, 設定你的 account 訊息與使用的 mail address (From address of mail), 便可以透過 API sendMail() 發送郵件. 簡單使用範例如下 : 
  1. public static void main(String[] args) {  
  2.     MailAgent mailAgent = new MailAgent();  
  3.     mailAgent.setUsername("your yahoo account");  
  4.     mailAgent.setPassword("password of your account");  
  5.     mailAgent.setFromAddress("from address of your mail");  
  6.     List toAddressList = new LinkedList();  
  7.     toAddressList.add("johnlee@ntnu.edu.tw"); // Add to-address1 of mail  
  8.     toAddressList.add("puremonkey2007@gmail.com"); // Add to-address2 of mail  
  9.     mailAgent.sendMail(toAddressList, "Hello Test""This is for testing");  
  10. }  
接著去你發送的信箱應該就可以看到上面代碼發送的測試 mail, 下面是我的 gmail 信箱收到的結果 : 
 

Supplement : 
How do I use the Yahoo SMTP server to send mail with the JavaMail API? 
TLS issue when sending to gmail through JavaMail

2012年9月3日 星期一

[ ML In Action ] Predicting numeric values : regression - Linear regression (1)

Preface : 
在前面的 kNNDecision tree etc, 都是做 discrete nominal value prediction 的 classification. 這邊要介紹的 "regression" 是指 Supervised learning 中對 continuous value 的預測. 通常你必須先決定 "方程式", 而方程式的變數值是由 test data set 提供, 而變數上的參數我們統稱為 regression weights. 而我們要做的便是找出最佳的 regression weights 讓方程式計算出來每個 test data set 出來的 "運算值" 與 "期待值" 間差的合為最小. 

Finding best-fit lines with linear regression : 
有了上面的介紹, 來看看 Linear regression 的特性 : 
Linear regression 
Pros: Easy to interpret result, computationally inexpensive
Cons: Poorly models nonlinear data
Works with: Numeric values, nominal values

這邊提的 regression 是指 linear regression, 書上的範例使用的 regression equation 如下 : 
HorsePower = 0.0015 * annualSalary - 0.99 * hoursListeningToPublicRadio

上面的 "annualSalary" 與 "hoursListeningToPublicRadio" 便是我們所謂的 feature(s), 而 "0.0015" 與 "0.99" 便是我們要求的 regression weights, 使得計算出來的 "HorsePower" 與實際上的 "HorsePower" 有最接近的結果. 底下為一般處理 regression 的過程 : 
General approach to regression
1. Collect: Any metod
2. Prepare: We'll need numeric values for regression.
3. Analyze: It’s helpful to visualized 2D plots. Also, we can visualize the regression weights if we apply shrinkage methods.
4. Train: Find the regression weights.
5. Test: We can measure the R2, or correlation of the predicted value and data, to measure the success of our models.
6. Use: With regression, we can forecast a numeric value for a number of inputs. This is an improvement over classification because we’re predicting a continuous value rather than a discrete category.

接著來看一些數學式子, 首先考慮我們有 training data 在 matrix X ; 而我們要求的是 regression weights 的 vector w. 因此我們可以計算出每一筆 data X1 的計算結果 : 
 

而考慮對應 data xi 的正確結果為 yi, 我們可以如下計算正確結果與公式推導結果的平方差 (squared error). 目標就是找出 regression weights 讓下面的式子的值為最小 (理想是等於0) : 
 

經過適當的數學推導(令上面式子等於0), 可以得到 regression weights vector w 的公式 : 
 

上面 regression weights vector w 帶帽子 "^" 是因為它是基於 Training data 與公式推導出來的最佳解, 不一定代表實際的最佳解 (Training data 只是部份的 data). 

接著我們要來看一個簡單範例, 考慮我們有 Training data 的分布如下 (ex0.txt) : 
 

接著我們要來撰寫函數 loadDataSet() 來從 ex0.txt 載入 Training data (regression.py): 
  1. #!/usr/local/bin/python  
  2. # -*- coding: utf-8 -*-  
  3. from numpy import *  
  4.   
  5. def loadDataSet(fileName):  
  6.     """ General function to parse tab -delimited floats. """  
  7.     numFeat = len(open(fileName).readline().split('\t')) - 1 #get number of fields  
  8.     dataMat = []; labelMat = []  
  9.     fr = open(fileName)  
  10.     for line in fr.readlines():  
  11.         lineArr =[]  
  12.         curLine = line.strip().split('\t')  
  13.         for i in range(numFeat):  
  14.             lineArr.append(float(curLine[i]))  
  15.         dataMat.append(lineArr)  
  16.         labelMat.append(float(curLine[-1]))  
  17.     return dataMat,labelMat  
可以如下載入 Training data : 
>>> import regression
>>> from numpy import *
>>> xArr, yArr = regression.loadDataSet('ex0.txt')
>>> xArr[0:2]
[[1.0, 0.067732000000000001], [1.0, 0.42781000000000002]]

再來是函數 standRegres() 用來計算 regression weights, 因為公式有用到反矩陣, 所以我們必須確定反矩陣存在 linalg.det(xTx) == 0.0 (代表反矩陣不存在), 代碼如下 : 
  1. def standRegres(xArr,yArr):  
  2.     xMat = mat(xArr); yMat = mat(yArr).T  
  3.     xTx = xMat.T*xMat  
  4.     if linalg.det(xTx) == 0.0:  
  5.         print "This matrix is singular, cannot do inverse"  
  6.         return  
  7.     ws = xTx.I * (xMat.T*yMat)  
  8.     return ws  
接著我們可以如下計算 regression weights (xArryArr 已經載入 Training data): 
>>> ws = regression.standRegres(xArr, yArr)
>>> ws
matrix([[ 3.00774324],
[ 1.69532264]])

也就是說我們的 regression equation 會是 : 
Y = 1.69532264X + 3.00774324

接著我們可以利用 matlab 將該線性方程式畫出來 : 
>>> xMat = mat(xArr)
>>> yMat = mat(yArr)
>>> yHat = xMat * ws # yi = xi*w
>>> import matplotlib.pyplot as plt
>>> fig = plt.figure()
>>> ax = fig.add_subplot(111)
>>> ax.scatter(xMat[:,1].flatten().A[0], yMat.T[:,0].flatten().A[0])

>>> xCopy = xMat.copy()
>>> xCopy.sort(0)
>>> yHat = xCopy * ws
>>> ax.plot(xCopy[:,1], yHat)
[]
>>> plt.show()

繪出圖形如下 : 
 

Supplement : 
[ ML In Action ] Predicting numeric values : regression - Linear regression (1) 
[ ML In Action ] Predicting numeric values : regression - Linear regression (2) 
[ ML In Action ] Predicting numeric values : regression - Linear regression (3)

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...