###### tags: `JSF_教學` # 訓練課程 18 (t18) - 寄送 email: 使用 JavaMail ## SMTP Server 工作原理介紹 ![](https://i2.wp.com/blog.mailtrap.io/wp-content/uploads/2019/10/use-port-number-1.png?resize=768%2C486&ssl=1) Ref: [25, 2525, 465, 587, and Other Numbers: All About SMTP Ports | blog.mailtrap.io](https://blog.mailtrap.io/smtp-ports-25-465-587-used-for/) **SMTP/SMTPs (Simple Mail Transfer Protocol/Secure or SMTP over SSL)**: This is a protocol for sending email messages between servers. **SSL (Secure Sockets Layer)** and its successor, **Transport Layer Security (TLS)**, provide a way to encrypt a communication channel between two computers over the Internet. **STARTTLS** is an email protocol command that tells an email server that an email client wants to turn an existing insecure connection into a secure one. Because TLS and SSL are application-layer protocols, senders and receivers need to know that they are being used to encrypt emails during transit. That’s where STARTTLS comes into play. Ref: [Understanding SSL, TLS, and STARTTLS Email Encryption | www.sparkpost.com](https://www.sparkpost.com/resources/email-explained/ssl-tls-starttls-encyption/#:~:text=STARTTLS%20is%20an%20email%20protocol,connection%20into%20a%20secure%20one) ## SMTP Server 的設定 ### mailtrap.io Safe Email Testing for Staging & Development 重要功能: - Test HTML for support by basic email clients: Inspect and debug each part of your message, and check if it works fine for the most popular email clients. - Share inboxes with your team members Discuss your ideas with colleagues or demonstrate your progress to the customer: invite them to your inbox! Client 端 SMTP 參數: - host: "smtp.mailtrap.io" - port: 2525 - ssl: no - tls: yes - user: - password: ![](https://i.imgur.com/ZoyU9io.png) Free Plan features ![](https://i.imgur.com/o9BwLEW.png) ### gmail smtp 設定 使用 SMTPS 協定寄送郵件 設定步驟 1. 申請 gmail 帳號 2. 啟用二步驟驗證 ![](https://i.imgur.com/lpK5DbZ.png) 3. 產生應用程式密碼 ![](https://i.imgur.com/RXyrKL5.png) 4. 使用應用程式密碼進行身份鑑別 SMTPS 參數: - 外寄郵件 (SMTP) 伺服器: smtp.gmail.com - 需要安全資料傳輸層 (SSL):是 - 需要驗證:是 - 安全資料傳輸層 (SSL) 通訊埠:465 - 帳戶名稱: 完整電子郵件地址 - 密碼: 應用程式密碼 Ref: https://support.google.com/mail/answer/7126229?hl=zh-Hant 程式碼參考: https://stackoverflow.com/questions/1990454/using-javamail-to-connect-to-gmail-smtp-server-ignores-specified-port-and-tries ## JavaMail API ### API 操作流程 1. 放置 SMTP/SMTPS 相關參數到 [`java.util.Properties`](https://docs.oracle.com/javase/tutorial/essential/environment/properties.html) 物件 2. 提供先前的 `Properties` 物件及帳密, 存放到 [`javax.mail.Session`](https://javaee.github.io/javamail/docs/api/javax/mail/Session.html) 物件. 3. 建立 [`javax.mail.Message`](https://javaee.github.io/javamail/docs/api/javax/mail/Message.html) 物件, 代表要傳送的 email 訊息。需要提供的資料: - javax.mail.Session 物件 - Mail recipient (收件人) - Mail From (寄件人) - Mail Subject 郵件標題 - Mail Content 郵件內容(文字/HTML) 4. 使用 `javax.mail.Transport` 物件傳送郵件 ### Example: 使用 SMTP + TLS 協定寄送郵件 1. 放置 SMTP/SMTPS 相關參數到 [`java.util.Properties`] Ref: [SMTP properties](https://javaee.github.io/javamail/docs/api/com/sun/mail/smtp/package-summary.html) SMTP properties ```java= Properties prop = new Properties(); prop.put("mail.smtp.host", "smtp.exmple.com"); prop.put("mail.smtp.port", "587"); prop.put("mail.smtp.auth", "true"); prop.put("mail.smtp.starttls.enable", "true"); //TLS ``` SMTPS properties ```java= prop.put("mail.smtp.auth", "true"); prop.put("mail.smtp.startls.enable", "true"); // default host prop.put("mail.smtp.host", smtps.example.com); // default TLS port prop.put("mail.smtp.port", "465"); // prop.put("mail.smtp.debug", "true"); prop.put("mail.smtp.socketFactory.port", "465"); // Concrete object to create SMTP sockets prop.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); //If set to true, failure to create a socket using the specified socket factory class will cause the socket to be created using the java.net.Socket class. Defaults to true. prop.put("mail.smtp.socketFactory.fallback", "false"); ``` 2. 提供先前的 `Properties` 物件及帳密, 存放到 [`javax.mail.Session`](https://javaee.github.io/javamail/docs/api/javax/mail/Session.html) 物件. ```java= // Need to provide SMTP Host properties, username and password Session session = Session.getInstance(prop, // An anonymous sub-Class of Authenticator // The getPasswordAuthentication() is called when authenticating new javax.mail.Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } }); ``` 使用 Session.getInstance() 方法取得 Session 物件: ```java static Session getInstance(Properties props, Authenticator authenticator) ``` Username 及 Password 要放到 ['import javax.mail.PasswordAuthentication'](https://javaee.github.io/javamail/docs/api/index.html?javax/mail/PasswordAuthentication.html) 物件中。 Applications use this class by creating a subclass, and registering an instance of that subclass with the session (`javax.mail.Session` Object) when it is created. When authentication is required, the system will invoke a method on the subclass (like getPasswordAuthentication). 3. 建立 [`javax.mail.Message`] ```java= Message message = new MimeMessage(session); message.setFrom(new InternetAddress("from@gmail.com")); message.setRecipients( Message.RecipientType.TO, InternetAddress.parse("to_username_a@gmail.com, to_username_b@yahoo.com") ); message.setSubject("Testing Gmail TLS"); message.setText("Hello, I'm testing the mail"); ``` `javax.mail.Message` 為抽象類別; 使用 [`javax.mail.internet.MimeMessage`](https://javaee.github.io/javamail/docs/api/javax/mail/internet/MimeMessage.html#MimeMessage-javax.mail.Session-) 實作類別建立 `Message` 物件。 電子郵件地址使用 [`javax.mail.internet.InternetAddress`](https://javaee.github.io/javamail/docs/api/javax/mail/internet/InternetAddress.html) 物件表示。 依據 RFC822 標準, Internet Address 的字串表示方式為: `"user@host.domain"` or `"Personal Name <user@host.domain>"`. 4. 使用 `javax.mail.Transport` 物件傳送郵件 SMTP ```java= Transport.send(message, message.getAllRecipients()); ``` SMTPS ```java= Transport transport = session.getTransport("smtps"); transport.sendMessage(message, message.getAllRecipients()); transport.close(); ``` ## 實作 1 寄信到 mailtrap.io ### 1. 申請 mailtrap.io 帳號 ### 2. Clone the project https://github.com/hychen39/easymail.git ### 3. 編譯專案成 jar 檔 Compile, Test, and Package ``` mvn package ``` Compile and Package ``` mvn package -Dmaven.test.skip=true ``` Ref: https://stackoverflow.com/questions/7456006/maven-package-install-without-test-skip-tests Output file: `target/easymail-1.0.jar` ### 4. 註冊 jar 檔到 Maven Local Repository ``` mvn install:install-file -Dfile=target/easymail-1.0.jar -DpomFile=./pom.xml ``` ``` $ mvn install:install-file -Dfile=target/easymail-1.0.jar -DpomFile=./pom.xml [INFO] Scanning for projects... [INFO] [INFO] -----------------------< org.hychen39:easymail >------------------------ [INFO] Building easymail 1.0 [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-install-plugin:2.5.2:install-file (default-cli) @ easymail --- [INFO] Installing D:\temp\easymail\target\easymail-1.0.jar to C:\Users\user\.m2\repository\org\hychen39\easymail\1.0\easymail-1.0.jar [INFO] Installing D:\temp\easymail\pom.xml to C:\Users\user\.m2\repository\org\hychen39\easymail\1.0\easymail-1.0.pom [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 0.878 s [INFO] Finished at: 2020-11-07T15:07:02+08:00 [INFO] ------------------------------------------------------------------------ ``` Ref: https://maven.apache.org/guides/mini/guide-3rd-party-jars-local.html ### 5. 建立 Maven Java 專案, 並加入 Dependency 建立一個 Maven Java Project. 加入以下的 dependency: ```xml= <dependencies> <dependency> <groupId>org.hychen39</groupId> <artifactId>easymail</artifactId> <version>1.0</version> </dependency> </dependencies> ``` ![](https://i.imgur.com/pjY0O6V.png) ### 6. 使用 org.hychen39.easymail package 撰寫 email 程式 ```java= public class App { public static void main(String[] args){ String username = "your_username"; String password = "your_password"; // Prepare the EmailEntity EmailEntity email = new EmailEntity(); email.setRecipient("user1@example.com") .setSender("usedbook106@gmail.com") .setUsername(username) .setPassword(password) .setSubject("Testing the java mail api") .setContents("Testing mailtrap.io smtp"); //Create the SMTP Host Properties Properties props = SmtpHostPropertyBuilder.getStmpProp("smtp.mailtrap.io", "2525"); MailByServerProtocal mailByMailtrapSMTP = new MailByMailtrapSMTP(); mailByMailtrapSMTP.setEmailEntity(email).setSmtpHostProperties(props); if ( mailByMailtrapSMTP.sendMail()) System.out.println("Mail successfully"); else System.out.println("Mail failed"); } } ``` ## References: 1. [JavaMail API – Sending email via Gmail SMTP example](https://mkyong.com/java/javamail-api-sending-email-via-gmail-smtp-example/) 1. [Jakarta Mail Tutorial](https://blog.mailtrap.io/jakarta-mail-tutorial/) 2. [JavaMail Gmail SMTP服務器](http://tw.gitbook.net/javamail_api/javamail_api_gmail_smtp_server.html) 3. [Sending an Email using the JavaMail API](https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/javamail/javamail.html) 4. [Jakarta Mail API documentation](https://eclipse-ee4j.github.io/mail/docs/api/) 5. [沒有mail server怎麼測試寄送email?快放過你的gmail來看看有那些可以測試用的smtp mail server](https://blog.alantsai.net/posts/2017/12/test-smtp-server-for-sending-mail-in-development)