SESでのドメイン検証を行うCDKコードを書いてみた

Agaroot IT Partners(AITP)のtomoです。

SESはお使いでしょうか。SESならば、マネジメントコンソール画面からでもメール送信で使用するドメインの設定を比較的簡単に行えるかと思います。

しかし、手動設定での誤操作が心理的に怖い場合や、簡単な操作でも手順書の作成が職場で徹底されている場合などは、手動設定を忌避したくなるでしょう。また、Lambda関数などでメール送信処理を実装する必要もあるので、ドメインのIDを作成してLambda関数のロールにメール送信を行うポリシーの付与するまでの設定をIaCで行いたい、といったことも考え得るかと思います。

そこで、CDKでSESでのドメイン検証を行うCDKコードを書いてみました。これで手動設定を避けられます。

SESとは

AWSの代表的なサービスですでにご存知の方、ご利用中の方も多いかと思いますが、復習も兼ねてSESの概要について触れます。

SESとはAWSのメールに関するサービスで、これを用いればメールの送受信を簡単に行うことができます。
https://aws.amazon.com/jp/ses/

今回取り上げていくように、Route 53などで保有しているドメインを検証というプロセスを経て使えるようにしたり、DKIMなどのメール認証を簡単に実現できたりします。

ということで、早速ですが下記より本題に入っていきます。

ソースコード

下記GitHubリポジトリにソースコードをプッシュしております。

https://github.com/aitp-tomo/mail-cdk

README.mdに記載された手順をもとにソースコードを試してみてください。

前提条件

上記GitHubリポジトリのREADME.mdにも記載しましたが、Route 53 のホストゾーンのルートドメインのドメイン検証を行うので、ホストゾーン名が検証するドメインと一致するパブリックホストゾーンが必要です。
例えばsub.example.comというドメインでメールを送信したい場合には、sub.example.comという名前のパブリックホストゾーンを作成してください。

また、mail.{検証するドメイン}というMX レコードおよび TXT レコードを作成するので、既存でそういったレコードがある場合には削除するか、ソースコードを変更いただく必要がございます。

CDKコードの詳細

今回最も重要なソースコードは lib/wrapper/SESWrapper.ts です。

import * as ses from "aws-cdk-lib/aws-ses";
import * as route53 from "aws-cdk-lib/aws-route53";
import { Route53Wrapper } from "./Route53Wrapper";
import { WrapperBase, WrapperBaseProps } from "./WrapperBase";

interface Props extends WrapperBaseProps {
  route53Wrapper: Route53Wrapper;
}

export class SESWrapper extends WrapperBase {
  private route53Wrapper: Route53Wrapper;
  public emailIdentity: ses.EmailIdentity;
  private domain: string;

  constructor(props: Props) {
    super(props);

    this.initialize(props);
  }

  private readonly initialize = (props: Props): void => {
    this.setAdditionalValues(props);
    this.createEmailIdentity();
    this.createRecords();
  };

  private readonly setAdditionalValues = (props: Props): void => {
    const { route53Wrapper } = props;
    this.route53Wrapper = route53Wrapper;
    this.domain = `mail.${this.route53Wrapper.hostedZone.zoneName}`;
  };

  private readonly createEmailIdentity = (): void => {
    this.emailIdentity = new ses.EmailIdentity(
      this.scope,
      `${this.appId}-email-identity`,
      {
        identity: ses.Identity.publicHostedZone(this.route53Wrapper.hostedZone),
        mailFromDomain: this.domain,
      }
    );
  };

  private readonly createRecords = (): void => {
    this.emailIdentity.dkimRecords.forEach((record, index) => {
      const id = `${this.appId}-dkim-record${index + 1}`;
      new route53.CnameRecord(this.scope, id, {
        domainName: record.value,
        zone: this.route53Wrapper.hostedZone,
        recordName: record.name,
      });
    });
  };
}

ソースコードを見ていただくとお分かりかと思いますが、

  1. 別インスタンスで取得しておいたホストゾーンの情報を受け取る
  2. 関数createEmailIdentityでドメインのIDを作成する
  3. 関数createRecordsでDKIMの設定に必要なレコードを作成する

といった流れで処理を行っていきます。2. の時点でID作成時にドメイン検証に必要なDNSレコードも作成されるので、1.~2. を行えばドメイン検証自体はできるようになります。

動作確認

今回のCDKコードでデプロイを行った後SESのマネジメントコンソール画面を確認するとドメイン検証やDKIMの設定が完了していることがわかります。

テストメールを送信してみると、DKIM含めて認証が通って無事にメールが送られてきました。下の画像はGmailでソースを表示した結果の一部です。

まとめ

いかがだったでしょうか。これでSESでのドメイン検証も、手動設定を行うことなくIaCでできますね。

今回は行いませんでしたが、例えば複数ドメインを一度に検証できるようにしてみたり、あるいは冒頭でお話ししたようにメール送信処理ができるようにしてみたりと、色々応用が効くのではと思います。

ぜひ今回のCDKコードを参考にしてみてください👋

関連するタグ