Nodemailerを使って 認証のためのメールを 送信したい

# 1. はじめに
SignUp時（アカウント登録時）、認証リンクを送信したり認証コードを入れたメールを送信したりして、登録されたメールアドレスが実際に使われているかを判定する必要があります。

トークンを含めた認証リンクを送るにしろ認証コードを送るにしろ、大抵は認証用の値をデータベースに控えておいて、ユーザーのアクセスやフォームへ入力されたコードとの比較に基づいてメールを認証することになります。

Next.jsを用いたアプリでメールを送るとき、nodemailerを用いて自動メール送信機能を実装したので、忘備録も兼ねて紹介します。

# 目次
- [1. はじめに](#1-はじめに)
- [2. nodemailerの下準備](#2-nodemailerの下準備)
- [3. コードの設定と保存](#3-コードの設定と保存)
- [4. リッチなメール設定](#4-リッチなメール設定)
- [5. おわりに](#5-おわりに)
- [6. 参考](#6-参考)

# 2. nodemailerの下準備
今回は、Gmailを使います。
自前のGmailアカウントを使う時は、事前に二段階認証を設定しておき、アプリケーション用のパスワードも登録しておく必要があります。手順は次の通りです。
<br>
①：二段階認証を設定する。

![Screenshot 2024-02-12 at 00-01-06 セキュリティ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2826164/41cbf51f-06d2-66cc-f002-a7fe8e37bae9.png)
<br>
②：アプリパスワードを設定する。
googleアカウントから以下のような画面を見つけることができると思います。
もし見つけられなければ、検索窓から探してみるとよいと思います。

![Screenshot 2024-02-28 at 21-13-33 アプリ パスワード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2826164/41d6c998-0eba-ac55-797c-dc6bfd0eac49.png)
※黒塗りのところはプロジェクト名を表しています

環境変数にメールアドレスとパスワードを設定したうえで、Next.jsで次のように変数を設定します。
```
MAIN_ACCOUNT=public.example.info@gmail.com
MAIN_PASS=**************** 

```

# 3. コードの設定と保存
基本的なコードは以下のような感じです。
nodemailerオブジェクトのcreateTransportメソッドを用いてtransporterを作ります。サービス名はgmailで、authのところに環境変数として設定した値を入力していきます。

```typescript:sendGmail.tsx
async function sendGmail(email: string, code: number, name: string): Promise<string | undefined> {
  const transporter = nodemailer.createTransport({
    service: "gmail",
    auth: {
      user: process.env.MAIL_ACCOUNT,
      pass: process.env.MAIL_PASS,
    },
  });

  const mailOptions = {
    from: process.env.MAIL_ACCOUNT,
    to: email,
    subject: "メール認証",
    text: `${name}さん、こんにちは！認証コードは${code}です！お早めに登録を完了させてください。`,
  };

  try {
    const info = await transporter.sendMail(mailOptions);
    console.log(info);
  } catch (error) {
    console.log(error);
    return "Failed to send Gmail.";
  }
}
```
transporterのsendMailメソッドの引数にメールオプションを渡してあげると、無事メールを送ることができます。
メールオプションにはメールを送信する際の設定をそのまま定義するようなイメージです。fromプロパティに自前のGmailアドレスを、toプロパティにフロントで受け取ったユーザーのメールアドレスを、subjectにメールの件名を、そしてtextにメール本文を入力します。

ちなみに、sendMailメソッドの返り値は以下の通りです。
```
{
  accepted: [ 'public.example.recipient@gmail.com' ],
  rejected: [],
  ehlo: [
    'SIZE 35882577',
    '8BITMIME',
    'AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH',
    'ENHANCEDSTATUSCODES',
    'PIPELINING',
    'CHUNKING',
    'SMTPUTF8'
  ],
  envelopeTime: 1420,
  messageTime: 1433,
  messageSize: 59463,
  response: '250 2.0.0 OK  1709120014 j11-20020a170902f24b00b001dbcf7f7752sm3118597plc.46 - gsmtp',
  envelope: {
    from: 'public.example.info@gmail.com',
    to: [ 'public.example.recipient@gmail.com' ]
  },
  messageId: '<78c3125f-6bd0-21a8-cb2e-dd2be10c1132@gmail.com>'    
}

```
# 4. リッチなメール設定
さて、これだけの設定でメール送信機能を実装することができました。かなりの手間を省いてメール送信を自動化することができ、それだけでもこのライブラリーは大変有用ですが、メールの内容がテキスト本文だけというのも味気ありません。
実は、このメールはhtml形式で、画像データも差し挟んで送ることができます。
以下が、具体的なコードです。

```diff_typescript:sendRichMail.tsx
async function sendGmail(email: string, code: number, name: string): Promise<string | undefined> {
      const transporter = nodemailer.createTransport({
        service: "gmail",
        auth: {
          user: process.env.MAIL_ACCOUNT,
          pass: process.env.MAIL_PASS,
        },
      });
      
+     const sendHTML = `
+         <!DOCTYPE html>
+         <html lang = "ja">
+         <head>
+         <title>Inquiry In College</title>
+             <meta content = "text/html; charset = utf-8" http-equiv = "Content-Type"/>
+             <meta content = "width = device-width" name = "viewport"/>
+         </head>
+         <body>
+            <div class = "main">
+                <div><img src="cid:logo" alt="logo"></div>
+                <h2>${name}様、ようこそ！</h2>
+                <p>ご登録くださり、ありがとうございます。認証コードは${code}です。お早めにご入力ください。</p>
+                <br/>
+                <p>もし身に覚えのないメールであれば、ご放念ください。</p>
+                <br/>
+            </div>
+         </body>
+    </html>
+    `;

      const mailOptions = {
        from: process.env.MAIL_ACCOUNT,
        to: email,
        subject: "メール認証",
        text: "No reply",
        html: sendHTML,
+       attachments: [
+         {
+           filename: "PublicLogo.jpg",
+           path: "public/PublicLogo.jpg",
+           cid: "logo",
+         },
+       ],
      };

    try {
        const info = await transporter.sendMail(mailOptions);
        console.log(info);
      } catch (error) {
        console.log(error);
        return "Failed to send Gmail.";
      }
    }

```
ポイントは二つです。
一つ目は、mailOptionにhtmlプロパティをつけて、そこにhtml形式で書いたコードをあてたこと。

二つ目は、画像を差し挟んだことです。mailOptionのattachmentプロパティにおいて、ファイルの名前とそのパス、そしてhtml内のimgタグからの参照に対応する値を入力しました。実際に、htmlのimgタグのsrcは`"cid:logo"`となっています。

attachmentのファイルパスは、Next.jsの場合においてはルートディレクトリからのパスになります。たいていの場合、画像を保存しているpublicディレクトリはデフォルトで、appディレクトリないしsrcディレクトリと同階層になると思うので、そのまま`public/someImage.png`と指定してあげたら大丈夫です。

# 5. おわりに
体感、結構サクサク進めて驚きでした。メールの自動送信はもっと面倒なイメージがあったので、予想よりもすらすら実装できてうれしかったです。ライブラリー様様って感じです。

## 6. 参考

[nodemailer でメールを送信する方法](#https://nodejs.keicode.com/nodejs/nodemailer.php)
[nodemailerでGmailから送信するための方法](#https://qiita.com/hshimo/items/ac599f5f25a3fa105ddd)