iT邦幫忙

2023 iThome 鐵人賽

DAY 12
0
Software Development

救救我啊我救我!CRUD 工程師的惡補日記系列 第 12

【Spring Boot】使用 Java Mail 發送純文字郵件與附件

  • 分享至 

  • xImage
  •  

發送郵件是相當常見的功能,許多網路平台光是註冊會員就要寄確認信給使用者了。或者是忘記密碼、購物網站下單、銀行的對帳單等情境,也都會透過 email 來通知。

本文將示範在 Spring Boot 專案串接電子郵件服務,接著發送純文字郵件,並攜帶附件。而後續的文章則會示範如何發送內嵌圖片的 HTML 郵件。


一、取得 Google 應用程式密碼

在串接外部服務時,通常都需要那個平台的帳密,郵件服務也不例外。筆者在本文選擇採用 Gmail 來寄信。然而 Google 為了安全性考量,不讓我們直接在程式中使用 Google 密碼。因此接下來請依照指示,產生「應用程式密碼」。

在 Google 帳戶的首頁,前往「安全性」的頁籤,找到「登入 Google 的方式」,進入「兩步驟驗證」畫面。
https://ithelp.ithome.com.tw/upload/images/20230912/20131107cJU4ag62uN.png

從畫面最下方,進入「應用程式密碼」畫面。
https://ithelp.ithome.com.tw/upload/images/20230912/20131107kP7SmgrQWc.png

在畫面中為這次要建立的密碼取個名字。
https://ithelp.ithome.com.tw/upload/images/20230927/20131107A1BUtbEXVJ.jpg

按下「建立」後,即可得到 16 個字的應用程式密碼。請讀者將它記在別的地方,因為離開此畫面後,便無法再看到了。
https://ithelp.ithome.com.tw/upload/images/20230927/20131107E5IkoXq645.jpg

二、準備 Spring Boot 專案

完成取得應用程式密碼的前置工作後,就能準備程式專案了。筆者使用的 Java 版本為 17(zulu-17);Spring Boot 版本為 3.1.3;建置工具使用 Maven。

(一)添加依賴

請在 pom.xml 檔案添加「Spring Mail」的依賴。

<!-- Spring Boot Mail -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

另外在後面的實作,我們會在 Spring 元件中撰寫程式邏輯。因此請把「Spring Web」的依賴也添加進來。

<!-- Spring Web -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

(二)連線設定

請在 application.properties 檔案,添加以下參數。

# 郵件服務主機
spring.mail.host=smtp.gmail.com
spring.mail.port=587

# 郵件服務帳密
spring.mail.username=YOUR_GOOGLE_ACCOUNT@gmail.com
spring.mail.password=YOUR_APPLICATION_PASSWORD

# 傳輸協定
spring.mail.properties.mail.transport.protocol=smtp

# 是否向郵件服務驗證身份
spring.mail.properties.mail.smtp.auth=true

# 是否啟用 TLS(傳輸層安全),對通訊加密
spring.mail.properties.mail.smtp.starttls.enable=true

其中 spring.mail.username 請提供要用來寄信的 Gmail 地址;而 spring.mail.password 則提供第一節所產生的應用程式密碼。

(三)準備 Component

以下建立了一個專門用來寄信的 Spring 元件。

@Service
public class MailService {

    @Autowired
    private JavaMailSender mailSender;
    
    // TODO
}

JavaMailSender 是一個介面,Spring Mail 的函式庫會讀取前面在 application.properteis 寫下的參數,自行建立實作類(JavaMailSenderImpl)後注入進來。它其實是對 Java Mail 進行了封裝,讓我們容易使用。

三、純文字郵件

(一)發送郵件

準備就緒後,接下來讓我們實作發送純文字郵件的程式。以下設計的方法,分別接收了收件地址,以及郵件的主旨與內容。

@Service
public class MailService {

    @Autowired
    private JavaMailSender mailSender;

    public void sendPlainText(Collection<String> receivers, String subject, String content) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setTo(receivers.toArray(new String[0]));
        message.setSubject(subject);
        message.setText(content);

        mailSender.send(message);
    }
}

以上建立了 SimpleMailMessage 物件,並將相關資訊設置進去。然後呼叫 JavaMailSendersend 方法就能發送了。

其中 setTo 方法是用來設置一至多個收件地址,此外讀者亦可選擇 setCCsetBcc 等方法。

(二)讓名字顯示在寄件人

SimpleMailMessage 還有一個 setFrom 方法,是用來設置寄件者。雖然已經在 application.properties 定義了,但收件人所看到的寄件人,就僅僅只是 email 地址。而不像我們平常收到的信,通常會是一個名字。

若想在寄件人顯示自定義的名字,可在使用 setFrom 方法時,採用 名字<寄件人地址> 格式的寫法。

message.setFrom("Vincent Zheng<xxx@gmail.com>");

下圖是寄件人顯示 email 和自定義名字的差別。
https://ithelp.ithome.com.tw/upload/images/20230912/20131107flfJRtaEgh.jpg

四、攜帶附件

事實上,以前的網路標準並不允許傳送 ASCII 以外的字元,也不接受附件。後來新的標準被提出,叫做「多用途網際網路郵件擴展」(Multipurpose Internet Mail Extensions,MIME),之後才開放這麼做。

在 email 中攜帶附件是現今常見的需求。本節先介紹主要的寄信邏輯,再說明如何加入附件。

(一)主要邏輯

以下設計的方法,與第三節的純文字相比,新增了 DataSource 的集合。雖然 DataSource 是一個介面,但它的實作類別會裝載附件的資料。

@Service
public class MailService {

    @Autowired
    private JavaMailSender mailSender;

    public void sendPlainTextWithAttachments(Collection<String> receivers, String subject, String content, Collection<DataSource> attachments) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true);
            helper.setTo(receivers.toArray(new String[0]));
            helper.setSubject(subject);
            helper.setText(content);

            for (DataSource source : attachments) {
                helper.addAttachment(source.getName(), source);
            }

            mailSender.send(message);
        } catch (MessagingException e) {
            throw new RuntimeException(e);
        }
    }
}

首先建立一個 MimeMessage,它在最後會被 JavaMailSender 發送。

接著建立 MimeMessageHelper,並將 MimeMessage 傳入。這個 helper 能幫助我們對郵件設置一些資料。其中附件是透過 addAttachment 方法來添加,需要傳入在郵件中要顯示的名稱,以及附件資料本身。

附件是以 DataSource 作為在程式碼中傳遞的介面。下面將介紹如何將附件資料轉換成這種形式。

(二)附件取自現有檔案

有些附件可能是放在 local 伺服器上的,所以每個人收到的其實都一樣。例如公司 logo 或 QR code 的圖片。

以下的方法是將名為「logo.jpg」的檔案當成附件,回傳了 FileDataSource

private DataSource getTestFileDataSource() {
    return new FileDataSource("logo.jpg");
}

FileDataSource 也提供以 File 為參數的建構子。

private DataSource getTestFileDataSource() {
    new FileDataSource(new File("logo.jpg"));
}

(三)附件取自生成檔案

有些文件是要透過程式來生成的,例如匯出交易紀錄、電子發票的 PDF 檔,甚至是從雲端空間下載的產品圖片。然而它們可能僅止於程式碼中的變數而已(如 FileOutputStreamBufferedImage 等),不一定會被輸出成檔案。

面對這種情況,可以使用 ByteArrayDataSource。只要取得位元組陣列byte[]),並且知道 MIME 檔案類型即可。

下面提供一個範例,是取得 BufferedImage 的位元組陣列,轉換成 ByteArrayDataSource

private DataSource getTestByteArrayDataSource() {
    BufferedImage image = ImageIO.read(new File("qr_code.jpg"));
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    ImageIO.write(image, "jpg", os);

    byte[] bytes = os.toByteArray();
    ByteArrayDataSource imageSource = new ByteArrayDataSource(bytes, "image/jpeg");
    imageSource.setName("invoice.png");
}

至於 ByteArrayDataSource 建構子的第二個參數,是 MIME 檔案類型。可參考「常見 MIME 類型列表」,給予適當的值。

Ref:SpringBoot - 第二十七章 | JavaMailSender發送信件


今日文章到此結束!
最後推廣一下自己的部落格,我是「新手工程師的程式教室」的作者,請多指教/images/emoticon/emoticon41.gif


上一篇
【Spring Boot】使用 JPA 建立多對多關係
下一篇
【Spring Boot】使用 Java Mail 發送 HTML 郵件
系列文
救救我啊我救我!CRUD 工程師的惡補日記50
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言