【MATLAB】自動寄信功能

  • 1241
  • 0
  • 2018-12-26

夏恩不久前才發掘出這個功能。
不過也不意外,MATLAB 包山包海,寄個信還算正常發揮。

今天遇到的問題如下:
程式連續跑一段時間後,可能會出現一些硬體或者是使用者造成的錯誤。
若沒有及時發現,則會造成後續作業的困擾。
因此想寫個自動發Mail的功能,殊不知......

哪來的各種奇怪的錯誤啊!

最後測試結果如下

% MABLAB code
% 2017.08.16 - Shayne
%
% 寄信要設定起訖點。
% 起點就是寄件人,要設定帳號密碼,才能利用程式登入。
% 每間電子郵件供應商會有特定之SMTP伺服器。
% 終點是收件人,不限供應商,把位址寫對就好。

% 這裡把 username 和 mail 分開寫是有原因的!
% 因為有些郵件伺服器認定會比較嚴格,
% 等一下再討論這一塊。

username = 'my_user_name';
password = 'my_password';
mail = 'my_user_name@gmail.com';

setpref('Internet', 'E_mail', mail);
setpref('Internet', 'SMTP_Server', 'smtp.gmail.com');
setpref('Internet', 'SMTP_Username', username);
setpref('Internet', 'SMTP_Password', password);

% 這裡使用java的類別庫
myprops = java.lang.System.getProperties;
myprops.setProperty('mail.smtp.auth', 'true');

% 這兩句話不寫也不影響執行
% 預設就是 465 port 
myprops.setProperty('mail.smtp.socketFactory.class', 'javax.net.ssl.SSLSocketFactory');
myprops.setProperty('mail.smtp.socketFactory.port', '465');

% sendmail 格式為 (目的地,標題,內文,附件)
% 詳細用法請在 command window 打上 >>help sendmail
sendmail('destination@gmail.com', 'subject', 'message', 'attachments');

在上面的敘述中,特別要注意到的是每一家電子郵件供應商的伺服器不一樣。
像是Gmail的伺服器是:smtp.gmail.com;Yahoo的伺服器是:smtp.mail.yahoo.com 等等。
此外,一般公司也會有自己的郵件伺服器,格式大概是 mail.xxxxxx.com 之類的。

再來夏恩有稍微測試一下,

setpref('Internet', 'E_mail', mail);

在這句話裡面,不論是用 username 或是用 mail 這兩個變數都可以成功寄信,應該是因為Google他們允許多種登入的方式,像夏恩的公司就不能這樣玩。

到這邊先暫停一下。
雖然把程式寫好了,但還沒有設定我們的Gmail呢!
首先到Gmail的設定裡面。

然後到「轉寄和 POP/IMAP」這邊,取用POP和IMAP的功能。
記得要按下面的「儲存變更」。

還沒完,再來要到「我的帳戶」裡面去設定。


點選畫面左邊紅色框框的地方。

最後把「允許安全性較低的應用程式」這個開關打開。

這樣程式應該就可以執行了。
不過在這邊,我遇到一個問題。

程式執行後得到一個錯誤訊息:

Error using sendmail (line 171)
Could not connect to SMTP host: smtp.gmail.com, port: 25;
Connection timed out: connect

這邊試著把防火牆關掉,但是沒用。很多網友提出這個建議。
後來夏恩用VPN跳出公司的網域後就沒事了。
原來是公司還有一層防火牆,所以讓郵件無法寄送。

另外一個常出現的錯誤訊息是:

Error using sendmail (line 171)
Authentication failed.

這個問題也弄好久。
這個訊息最直接的原因是帳號或密碼錯誤。

可是網路上的教學都是寫:

username = 'my_user_name@gmail.com';
password = 'my_password';

用 username 就代表了整個 mail 的位址。
這在 gmail 不會有問題,但一旦換到公司的主機就掛了。
因為公司郵件系統是使用 "my_user_name" 和 "password" 登入,
寄信時,則是完整的位址 "my_user_name@my_campany.com",

當夏恩使用完整的郵件位址去登入時...
於是就一直出現 Authentication failed. 的錯誤。
真是個討人厭的小東西。

最後再附上另外一種使用 MATLAB 的寄信方式。
這是我再查找前面那些錯誤的時候,去跟同事借他寫好的VB.Net程式來參考。
從他的程式碼中挑出要的部分,改寫成 MATLAB 的語法。

程式如下:

% MABLAB code using .Net Assembly
% 2017.08.16 - Shayne

% 首先匯入 System.Net 這個 .Net 的類別庫 
NET.addAssembly('System.Net');
import System.Net.Mail.*;

username = 'my_user_name';
password = 'my_password';
mail = 'my_user_name@gmail.com';

% 設定起點跟終點
from = MailAddress('departure@gmail.com');
to = MailAddress('destination@gmail.com');

% 建立 MailMessage 物件
myMail = MailMessage(from, to);

% 設定標題和內容
myMail.Subject = 'Test';
myMail.Body = 'Test';

% 建立 SMTP 客戶端物件
mySmtpClient = SmtpClient();

% 要使用完整的位址,不能只有 username
mySmtpClient.Credentials = System.Net.NetworkCredential(mail, password);

% 設定SMTP伺服器
mySmtpClient.Host = 'smtp.gmail.com';

% 設定連接埠
% 經過測試,若使用 Port 465會產生錯誤訊息,如下:
% Message: SMTP 伺服器需要安全連接,或用戶端未經驗證。 伺服器回應為: 5.5.1 
% Authentication Required. Learn more at Source: System
mySmtpClient.Port = 25;
mySmtpClient.EnableSsl = true;

% 最後把信送出去 
mySmtpClient.Send(myMail);

附帶一提:
如果有遇到一些 MATLAB 沒有的功能,但可以從 VB 或 C# 實現時,
可以將程式寫成類別庫,也就是 .dll 檔,然後再用上面提到的 "NET.addAssembly" 加進來,
就可以擁有新功能囉!

除了 "NET.addAssembly" 之外,MATLAB 也可以吃 C++ 、java、python 等的類別庫,
不過要用不同的檔案格式就是了,這個有空再聊。