カテゴリー
【AWS Lambda使い方ガイド】NodemailerのAWS SESクライアントを使ってLambdaからEmailを送信してみる
※ 当ページには【広告/PR】を含む場合があります。
2024/10/26

ここ最近、nodemailerのEmail送信クライアントに
クライアント側からSESでメール送信
nodemailerのデフォルトSMTPとして良く紹介があるのはgmailアカウントでずが、『AWS SES』もメーラーとして選択することができます。
ローカルの環境変数にAWSのアカウント情報が
.env
AWS_ACCESS_KEY_ID="....";
AWS_SECRET_ACCESS_KEY="....";
以下のように、nodemailerクライアントを実装することで、ご自分の保有するSESメーラーアカウントから、メールを送信できる機能があります。
const nodemailer = require("nodemailer");
const aws = require("@aws-sdk/client-ses");
const ses = new aws.SES({
apiVersion: "2010-12-01",
region: "us-east-1",
});
const transporter = nodemailer.createTransport({
SES: { ses, aws },
});
ローカル上のアプリケーションで動かすならこれでEメール送信することも可能ですが、サーバーサイドで動かすとなるともう少し手を加える必要があります。
Lambdaハンドラにnodemailer-SESクライアントを組み込む
Lambdaのハンドラ関数で使うnodemailer/SESのパートの仕込みとしては以下のようなものになります。
import nodemailer from 'nodemailer';
import * as aws from "@aws-sdk/client-ses";
const ses = new aws.SES({
apiVersion: "2010-12-01",
region: "us-east-1", //👈自身のSESの設定済みリージョンであることを確認
});
export function sendEmail() {
//👇送信先のアドレス
const email = 'okurisaki@oaite.jp';
//👇送信する内容
const mail = {
from: 'hogehoge@piyopiyo.com',
to: email,
subject: 'SESからのメールです',
text: 'こんにちは!',
html: `<p>こんにちは!</p>`,
};
try {
const transport = nodemailer.createTransport({
SES: { ses, aws },
});
const result = await transport.sendMail(mail);
return JSON.stringfy(result);
} catch (err) {
return JSON.stringfy(err);
}
}
これでLambdaハンドラのどこかで
sendEmail
Lambdaに直接AWSクレデンシャル情報を環境変数としてセットできない
まずはうまく動かない例から紹介します。
ローカル環境だと
.env
AWS_ACCESS_KEY_ID="....";
AWS_SECRET_ACCESS_KEY="....";
では、Lamdaに直接これらのクレデンシャル情報を環境変数として指定して使ってみるとうまく行くのでは無いかと考えなしに設定してみます。
ダッシュボードからでも設定は出来ますが、今回は以下のようなCDKコードで設定するやり方で説明しますと、
import {
Stack,
StackProps,
aws_lambda,
//...中略
} from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkTacokinShopStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
//...いろいろ中略
const lambda = new aws_lambda.Function(this, 'Server', {
runtime: aws_lambda.Runtime.NODEJS_20_X,
code: aws_lambda.Code.fromAsset(join(__dirname, '../../build/lambda')),
handler: 'index.handler',
architecture: aws_lambda.Architecture.ARM_64,
memorySize: 128,
timeout: Duration.seconds(30),
environment: {
//☆👇クレデンシャル変数は直接Lambdaへ注入できない!
"AWS_ACCESS_KEY_ID": process.env.AWS_ACCESS_KEY_ID,
"AWS_SECRET_ACCESS_KEY": process.env.AWS_SECRET_ACCESS_KEY,
}
}).addFunctionUrl({
authType: aws_lambda.FunctionUrlAuthType.NONE,
invokeMode: aws_lambda.InvokeMode.RESPONSE_STREAM
});
//...以下略
Lambda関数のコンストラクタの設定プロパティである
envirnoment
つまり、LambdaへのAWSアカウント変数の直接の付与はセキュリティ上の観点から禁止されています。
ということで、サーバーサイドでSESにEmail送信権限を別の方法で与える必要が出てきます。
SES用のLamboda実行ロールを作成
先程は先に失敗する例から説明しましたが、リモートのLambdaから
@aws-sdk/ses
なお、SESの他にも、LambdaからS3、DynamoDBへアクセスする場合にも同じように適当な専用ロールが必要になります。
CDKからは、このSES用のポリシーを作成し、Lambdaのロールへ付与して使う必要があります。
import {
Stack,
StackProps,
aws_lambda,
aws_iam,
//...中略
} from 'aws-cdk-lib';
import { Construct } from 'constructs';
export class CdkTacokinShopStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
//...いろいろ中略
//👇Lambda用の基本ポリシー
const lambda_basic_policy = new aws_iam.ManagedPolicy(this, 'Lambda_basic_policy', {
managedPolicyName: 'lambda_basic_policy',
statements: [
new aws_iam.PolicyStatement({
effect: aws_iam.Effect.ALLOW,
actions: [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
resources: [
'arn:aws:logs:*:*:*'
],
}),
],
});
//☆👇SES用のメール送信ポリシー
const ses_sender_policy = new aws_iam.ManagedPolicy(this, 'Ses_sender_policy', {
managedPolicyName: 'ses_sender_policy',
statements: [
new aws_iam.PolicyStatement({
effect: aws_iam.Effect.ALLOW,
actions: [
"ses:SendEmail",
"ses:SendRawEmail"
],
resources: [
'*'
],
}),
],
});
//👇カスタムロールの作成
const ses_role = new aws_iam.Role(this, 'ses_sender_role', {
roleName: 'ses_sender_role',
assumedBy: new aws_iam.ServicePrincipal('lambda.amazonaws.com'),
});
//👇先ほど作成した2つのポリシーをアタッチ
ses_role.addManagedPolicy(lambda_basic_policy);
ses_role.addManagedPolicy(ses_sender_policy);
const lambda = new aws_lambda.Function(this, 'Server', {
runtime: aws_lambda.Runtime.NODEJS_20_X,
code: aws_lambda.Code.fromAsset(join(__dirname, '../../build/lambda')),
handler: 'index.handler',
architecture: aws_lambda.Architecture.ARM_64,
memorySize: 128,
timeout: Duration.seconds(30),
//☆👇カスタム実行ロールを指定
role: ses_role
}).addFunctionUrl({
authType: aws_lambda.FunctionUrlAuthType.NONE,
invokeMode: aws_lambda.InvokeMode.RESPONSE_STREAM
});
//...以下略
これでLambdaからでもnodemailer-SESクライアントでEmail送信が問題なく行えると思います。
まとめ
以上、LambdaからでもNodemailer/SESクライアントでメールを送信するためのポイントを解説してみました。
これで外部のEmail操作用のAPIサービスを利用せずとも、AWS内だけでメール送信用サービスが完結できるので、シンプルなビジネスを行う場合に最適かと思います。
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー