CLOVER🍀

That was when it all began.

aws-ses-v2-localを使って、Amazon SES API v2をローカルで試す

これは、なにをしたくて書いたもの?

Amazon SESをローカルで動作確認できるような代替ツールはないのかな?と思って調べてみたのですが。

LocalStackはAmazon SES v1は使えますが、v2はProでないと利用できないようです。

LocalStack Coverage / ses

LocalStack Coverage / sesv2

aws-ses-v2-localというものがあるようなので、こちらを試してみることにしました。

GitHub - domdomegg/aws-ses-v2-local: ☁📬 A local version of Amazon Simple Email Service (AWS SES) supporting the V1 and V2 API

Amazon SESのAPI

Amazon SES自体は、メールの送受信を行えるサービスです。

Amazon SESとは? - Amazon Simple Email Service

メール送信は、以下の3つの方法で行うことができます。

Amazon SESのE メール形式 - Amazon Simple Email Service

さらに、APIにはv1とv2があります。

Welcome - Amazon Simple Email Service

Welcome - Amazon Simple Email Service

LocalStackがサポートしていないのは、このv2です。

APIは、AWS SDKやAWS CLIなどから利用します。

Amazon SESとAWS SDKについての情報やサンプルは、こちらにまとまっています。

AWS SDK での Amazon SES の使用 - Amazon Simple Email Service

こちらのページからリンクされているAWS SDK for JavaScrpt v3のサンプルでは、v1のみでした。

https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javascriptv3/example_code/ses

AWS SDK for Java v2のサンプルでは、v2もv1もありました。

https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/javav2/example_code/ses

コード例のページ。

AWS SDK を使用した Amazon SES のコード例 - Amazon Simple Email Service

AWS SDK を使用した Amazon SES のコード例 - Amazon Simple Email Service

AWS SDK を使用した Amazon SES API v2 のコード例 - Amazon Simple Email Service

メール送信の例。

AWS SDK を使用して Amazon SES から E メールを送信する - Amazon Simple Email Service

AWS SDK を使用して Amazon SES API v2 E メールを送信する - Amazon Simple Email Service

aws-ses-v2-local

aws-ses-v2-localはAmazon SESのローカルバージョンで、APIはv1とv2の両方をサポートしています。

GitHub - domdomegg/aws-ses-v2-local: ☁📬 A local version of Amazon Simple Email Service (AWS SES) supporting the V1 and V2 API

SendEmailとSendRawEmailの両方のエンドポイントに重点を置いています。

テキストメール、HTMLメールのどちらも扱え、添付ファイルもOK。送信されたメールのViewerも持っています。

今回はこちらを使って、Amazon SES API v2を使ったメールの送信を試してみたいと思います。クライアントは、AWS SDK for JavaScript v3を
使います。

環境

今回の環境は、こちら。

$ node --version
v16.17.1


$ npm --version
8.15.0

AWS SDK for JavaScriptを使ったプログラムと、aws-ses-v2-localをインストールするディレクトリは別にします。

$ mkdir app tool

aws-ses-v2-localをインストールする

まずはaws-ses-v2-localをインストールします。この用途向けに作成したディレクトリ内に移動。

$ cd tool

インストール。

$ npm i aws-ses-v2-local

インストールされたバージョンは、こちら。

  "dependencies": {
    "aws-ses-v2-local": "^2.0.1"
  }

起動方法は、aws-ses-v2-localコマンドで起動するか、プログラム内で起動するかのどちらかです。

aws-ses-v2-local / Usage / Setting up aws-ses-v2-local

今回はaws-ses-v2-localコマンドで起動することにします。

$ npx aws-ses-v2-local

標準出力に出ているとおり、http://localhost:8005でリクエストを受け付けるようになります。

aws-ses-v2-local: starting server...
aws-ses-v2-local: server running at http://localhost:8005

なお、ブラウザでhttp://localhost:8005にアクセスするとWeb UIが表示されます。

もうひとつの起動方法は、以下のようにJavaScriptプログラム内で起動する方法ですね。

import server from 'aws-ses-v2-local'

server({ port: 8005 })
console.log('aws-ses-v2-local: server up and running')

aws-ses-v2-localは、Expressを使って作られているようです。

https://github.com/domdomegg/aws-ses-v2-local/blob/v2.0.1/src/index.ts

aws-ses-v2-localにアクセスするプログラムを作成する

では、aws-ses-v2-localを使うプログラムを作成しましょう。といっても、AWS SDK for JavaScript v3を使ってのアクセスですが。
確認は、テストコードで行うことにします。

アプリケーション用のディレクトリ内に移動。

$ cd /path/to/app

Node.js+TypeScriptのプロジェクトのセットアップ。

$ npm init -y
$ npm i -D typescript
$ npm i -D prettier
$ npm i -D @types/node@v16
$ npm i -D jest @types/jest
$ npm i -D esbuild esbuild-jest
$ mkdir src test

この時点での依存関係。

  "devDependencies": {
    "@types/jest": "^29.0.3",
    "@types/node": "^16.11.60",
    "esbuild": "^0.15.9",
    "esbuild-jest": "^0.5.0",
    "jest": "^29.0.3",
    "prettier": "^2.7.1",
    "typescript": "^4.8.3"
  },

scriptsの定義。

  "scripts": {
    "build": "tsc --project .",
    "build:watch": "tsc --project . --watch",
    "typecheck": "tsc --project ./tsconfig.typecheck.json",
    "typecheck:watch": "tsc --project ./tsconfig.typecheck.json --watch",
    "test": "jest",
    "format": "prettier --write src test"
  },

各種設定ファイル。

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "lib": ["esnext"],
    "baseUrl": "./src",
    "outDir": "dist",
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitOverride": true,
    "noImplicitReturns": true,
    "noPropertyAccessFromIndexSignature": true,
    "esModuleInterop": true
  },
  "include": [
    "src"
  ]
}

tsconfig.typecheck.json

{
  "extends": "./tsconfig",
  "compilerOptions": {
    "baseUrl": "./",
    "noEmit": true
  },
  "include": [
    "src", "test"
  ]
}

.prettierrc.json

{
  "singleQuote": true
}

jest.config.js

module.exports = {
  testEnvironment: 'node',
  transform: {
    "^.+\\.tsx?$": "esbuild-jest"
  }
};

あとは、AWS SDK for JavaScript v3をインストールします。

AWS SDK for JavaScript v3

今回は、Amazon SES API v2用のクライアントをインストール。

$ npm i @aws-sdk/client-sesv2

SESv2 Client - AWS SDK for JavaScript v3

  "dependencies": {
    "@aws-sdk/client-sesv2": "^3.178.0"
  }

これで、プログラムを書くまでの準備は完了です。

あとは、このあたりを参考にしつつ、プログラムを作成します。

aws-ses-v2-local / Usage / Setting up your application

作成したテストコード。

test/ses-v2-send-mail.test.ts

import {
  SendEmailCommand,
  SendEmailCommandInput,
  SESv2Client,
} from '@aws-sdk/client-sesv2';

test('Amazon SES API v2, sendMail test', async () => {
  const ses = new SESv2Client({
    endpoint: 'http://localhost:8005',
    region: 'us-east-1',
    credentials: {
      accessKeyId: 'dummy',
      secretAccessKey: 'dummy',
    },
  });

  const input: SendEmailCommandInput = {
    FromEmailAddress: 'from@example.com',
    Destination: { ToAddresses: ['to@example.com'] },
    Content: {
      Simple: {
        Subject: {
          Data: 'メールの件名です',
        },
        Body: {
          Text: {
            Data: `こんにちは。

                   Amazon SES v2 APIでSimpleメールを送ります。`,
          },
        },
      },
    },
  };


  const command = new SendEmailCommand(input);

  const output = await ses.send(command);

  expect(output.MessageId).not.toBeUndefined();
  expect(output.MessageId).toMatch(/^ses-\d+/);

  expect(output.$metadata.httpStatusCode).toBe(200);

  console.log(output);
});

Amazon SES API v2を使う時に、エンドポイントをhttp://localhost:8005(aws-ses-v2-localのエンドポイント)に指定する必要があります。

  const ses = new SESv2Client({
    endpoint: 'http://localhost:8005',
    region: 'us-east-1',
    credentials: {
      accessKeyId: 'dummy',
      secretAccessKey: 'dummy',
    },
  });

クレデンシャルは設定しないとAWS SDK for JavaScript v3が動作しませんが、値自体はなんでも良さそうです。

SendMail APIを使う際には、AWS SDK for JavaScript v3の以下あたりのAPIリファレンスを参照して書きました。

SendEmailCommand | SESv2 Client - AWS SDK for JavaScript v3

SendEmailCommandInput | SESv2 Client - AWS SDK for JavaScript v3

EmailContent | SESv2 Client - AWS SDK for JavaScript v3

Message | SESv2 Client - AWS SDK for JavaScript v3

動作確認

動かしてみます。

$ npm test

テストの結果。

> app@1.0.0 test
> jest

  console.log
    {
      '$metadata': {
        httpStatusCode: 200,
        requestId: undefined,
        extendedRequestId: undefined,
        cfId: undefined,
        attempts: 1,
        totalRetryDelay: 0
      },
      MessageId: 'ses-338985724'
    }

      at Object.<anonymous> (test/ses-v2-send-mail.test.ts:34:11)

 PASS  test/ses-v2-send-mail.test.ts
  ✓ Amazon SES API v2, sendMail test (68 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.574 s, estimated 1 s
Ran all test suites.

SendEmailCommandの実行結果はSendMailCommandOutputですが、aws-ses-v2-localの場合はどんなレスポンスが返ってきているか
わかるように、console.logで出力もしています。

    {
      '$metadata': {
        httpStatusCode: 200,
        requestId: undefined,
        extendedRequestId: undefined,
        cfId: undefined,
        attempts: 1,
        totalRetryDelay: 0
      },
      MessageId: 'ses-338985724'
    }

SendEmailCommandOutput | SESv2 Client - AWS SDK for JavaScript v3

メールを送信した後、http://localhost:8005/にアクセスするとaws-ses-v2-localのWeb UI上で送信されたメールを確認できます。

さらにメールを追加。

タイムスタンプの新しい方から上に並んでいきます。

aws-ses-v2-localに送信されたメールは配列で保持しているので、再起動するとデータがなくなります。まあ、困らないでしょうけれど。

https://github.com/domdomegg/aws-ses-v2-local/blob/v2.0.1/src/store.ts#L23-L25

こんな感じでしょうか。

まとめ

aws-ses-v2-localを使って、Amazon SES API v2を試してみました。

SendEmailの方しか試していませんが、割と簡単に使えたので良さそうです。

SendRawEmailやその他の機能は、また気になった時に試すことにします。