お久しぶりです。
最近、フロントエンドのお仕事に従事をしている中の人です。
以前にブログ記事に書いた CDK で AWS SES を作ってみた という記事はご覧いただけましたでしょうか。
ご覧になっていない人は見ていただければと思います。
本記事はその記事の続きになります。
作ったもの
SESでメール転送するCDKです。
SESで生やしたメールアドレスに、メールが届いたら指定したメールアドレスに転送するものを作りました。
無駄に添付ファイルも転送するという抜かりない実装です。
リポジトリ
使い方も README.md に書いてあります。
ご参照ください。
アーキテクチャ
AWS SES / S3 / Lambda というシンプルな構成です。
- SES でメールを受信したら、S3にメール情報を保管。
- Lambdaを起動してS3にあるメール情報を取得し、指定したメールアドレスへメール情報を転送。
をしています。
詰まったところ
SES に Lambda をくっつけてイベントをもらってもメール情報はない
AWS SES の受信設定で、Lambdaが選べることは知っていました。
そのため、「メールを受信したら、Lambdaを起動してイベントの中にある情報を使って転送すればOKじゃん」みたいなことを考えていました。
しかし、実際には、メールの本文情報は入っていないです。
そのため、 S3 にメール本文をいれてLambdaで拾ってくる みたいなことをしています。
ちなみに、Lambdaで受け取るSESの情報は以下。
{
"Records": [
{
"eventSource": "aws:ses",
"eventVersion": "1.0",
"ses": {
"mail": {
"timestamp": "2025-04-17T12:39:34.969Z",
"source": "******m",
"messageId": "******",
"destination": [
"SES_MAIL_ADDRESS"
],
"headersTruncated": false,
"headers": [
{
"name": "Return-Path",
"value": "<******m>"
},
{
"name": "Received",
"value": "from e234-2.smtp-out.ap-northeast-1.amazonses.com (e234-2.smtp-out.ap-northeast-1.amazonses.com [23.251.234.2]) by inbound-smtp.ap-northeast-1.amazonaws.com with SMTP id ****** for SES_MAIL_ADDRESS; Thu, 17 Apr 2025 12:39:34 +0000 (UTC)"
},
{
"name": "Received-SPF",
"value": "pass (spfCheck: domain of mail.aws.autumn-color.com designates 23.251.234.2 as permitted sender) client-ip=23.251.234.2; envelope-from=******m; helo=e234-2.smtp-out.ap-northeast-1.amazonses.com;"
},
{
"name": "Authentication-Results",
"value": "amazonses.com; spf=pass (spfCheck: domain of mail.aws.autumn-color.com designates 23.251.234.2 as permitted sender) client-ip=23.251.234.2; envelope-from=******m; helo=e234-2.smtp-out.ap-northeast-1.amazonses.com; dkim=pass [email protected]; dkim=pass [email protected]; dmarc=pass header.from=aws.autumn-color.com;"
},
{
"name": "X-SES-RECEIPT",
"value": "*****"
},
{
"name": "X-SES-DKIM-SIGNATURE",
"value": "****"
},
{
"name": "DKIM-Signature",
"value": "****"
},
{
"name": "DKIM-Signature",
"value": "******"
},
{
"name": "From",
"value": "SES_MAIL_ADDRESS"
},
{
"name": "To",
"value": "SES_MAIL_ADDRESS"
},
{
"name": "Subject",
"value": "aaa"
},
{
"name": "MIME-Version",
"value": "1.0"
},
{
"name": "Content-Type",
"value": "text/html; charset=UTF-8"
},
{
"name": "Content-Transfer-Encoding",
"value": "quoted-printable"
},
{
"name": "Message-ID",
"value": "<0106019643c2fe70-01c9b657-03e7-4680-b70d-841ec51460c0-000000@ap-northeast-1.amazonses.com>"
},
{
"name": "Date",
"value": "Thu, 17 Apr 2025 12:39:34 +0000"
},
{
"name": "Feedback-ID",
"value": "::1.ap-northeast-1.z/aeDskmBB8vGsMr5LSN5IbWhbzIn7+kspXDou76DTs=:AmazonSES"
},
{
"name": "X-SES-Outgoing",
"value": "2025.04.17-23.251.234.2"
}
],
"commonHeaders": {
"returnPath": "******m",
"from": [
"SES_MAIL_ADDRESS"
],
"date": "Thu, 17 Apr 2025 12:39:34 +0000",
"to": [
"SES_MAIL_ADDRESS"
],
"messageId": "<0106019643c2fe70-01c9b657-03e7-4680-b70d-841ec51460c0-000000@ap-northeast-1.amazonses.com>",
"subject": "aaa"
}
},
"receipt": {
"timestamp": "2025-04-17T12:39:34.969Z",
"processingTimeMillis": 243,
"recipients": [
"SES_MAIL_ADDRESS"
],
"spamVerdict": {
"status": "DISABLED"
},
"virusVerdict": {
"status": "DISABLED"
},
"spfVerdict": {
"status": "PASS"
},
"dkimVerdict": {
"status": "PASS"
},
"dmarcVerdict": {
"status": "PASS"
},
"action": {
"type": "Lambda",
"functionArn": "arn:aws:lambda:ap-northeast-1:****",
"invocationType": "Event"
}
}
}
}
]
}
メール受信ルールの有効化
メールの受信ルールを設定だけしても、メールは受信されないです。
メールの受信ルールの有効化をする必要があります。
コードでいうと、以下の箇所( コードでいうと app/lib/app-stack.ts
)がルール有効化の箇所です。
// SES の受信ルール有効化
new cr.AwsCustomResource(this, `${PREFIX}EnableReceiptRuleSet`, {
onCreate: {
service: 'SES',
action: 'setActiveReceiptRuleSet',
parameters: {
RuleSetName: ruleSet.receiptRuleSetName,
},
physicalResourceId: cr.PhysicalResourceId.of(`Activate-${ruleSet.receiptRuleSetName}`),
},
onUpdate: {
service: 'SES',
action: 'setActiveReceiptRuleSet',
parameters: {
RuleSetName: ruleSet.receiptRuleSetName,
},
physicalResourceId: cr.PhysicalResourceId.of(`Activate-${ruleSet.receiptRuleSetName}`),
},
onDelete: {
service: 'SES',
action: 'setActiveReceiptRuleSet',
parameters: {
RuleSetName: '',
},
physicalResourceId: cr.PhysicalResourceId.of(`Activate-${ruleSet.receiptRuleSetName}`),
},
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
})
});
onCreate
と onUpdate
と onDelete
がある理由は、ルールを変更したときや削除した時の実行はどうするかを書いています。
はじめは onCreate のみで作っていましたが、試行錯誤していてルール変更したときに CDK から怒られたり、変更後自動でルールが有効化しなかったりしました。
以下の ISSUE より、onDelete
を実装しろとのことなのでちゃんと実装しました。ついでに、 onUpdate
もした。
エラーメッセージは以下。
Received response status [FAILED] from custom resource. Message returned: User: arn:aws:sts::***:assumed-role/*** is not authorized to perform: ses:DeleteReceiptRuleSet because no identity-based policy allows the ses:DeleteReceiptRuleSet action (RequestId: ***)
Lambdaの初期化がおわらない
LambdaをCDKといっしょにデプロイするとき、Docker でのビルドが走らせるため、コンテナのセットアップが入ります。
その時に、ずっと RUN npm install --global [email protected]
で止まっていました。
この場合、ローカルで動かして言えるCPUのアーキテクチャを揃えるとうまくいくっぽいです。
中の人の場合、M4 macBook なので cdk.aws_lambda.Architecture.ARM_64
を追記したらうまくいった。
const lambdaFunction = new cdk.aws_lambda_nodejs.NodejsFunction(this, `${PREFIX}LambdaFunction`, {
entry: 'lambda/src/index.ts',
handler: 'handler',
runtime: cdk.aws_lambda.Runtime.NODEJS_22_X,
memorySize: 128,
timeout: cdk.Duration.seconds(30),
architecture: cdk.aws_lambda.Architecture.ARM_64, // これ
// 略
});
CustomResource を変更して deploy したらエラーになった
CustomResource を変更して 再度デプロイみたいなことをしたら以下のエラーになりました。
****/Resource/Default (***) Modifying service token is not allowed.
この場合、AwsCustomResource
に functionName
を固定化していることが原因らしいです。
new cr.AwsCustomResource(this, `${PREFIX}EnableReceiptRuleSet`, {
functionName: `${PREFIX}EnableReceiptRuleSet`, // ←これ
内部的に作られる Lambda の名前を指定してしまっているため、CDK が更新のたびにそれを「既存の名前で上書きしよう」としてしまい、そのときに ServiceToken が変更される=CloudFormation 的に禁止、という事になっている
とのことです。
(chatGPT 曰く)
皆様も気をつけましょう。
添付ファイルも転送したい
現時点(2025/04)において、LambdaでSESを使ったメール送信には、 @aws-sdk/client-ses
を使います。
このパッケージをつかうと簡単にメール送信ができてしまいますが、
メールを作るためには、 SendEmailCommand
と SendRawEmailCommand
の2種類があります。
前者はお手軽で、後者はフルマニュアルでガシガシメールの仕様に従って書く必要があります。
メールの文章だけなら SendEmailCommand
で十分対応できます。
しかし、添付ファイルも転送したい場合は、SendRawEmailCommand
を使う必要があります。
幸いにも、中の人が chatGPT と共に書いたサンプルコードがあるのでご参照ください。
まとめ
AWS SESで受けたメールをそのまま転送するCDKを作ってみました。
躓いた点も書いたので、同じ問題にぶちあった人は是非参考にしてみてください。
参考文献

