1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

cdkでsnsのtopicとsubscriptionを作ってlambdaからpublishしたメモ

Last updated at Posted at 2023-06-22

概要

メールをlambdaからSNSを通して送信するサンプル。

ソースコード

コード

cdk/lib/alarm-sns-stack.ts
import { Aspects, CfnOutput, Stack, StackProps, Tag } from "aws-cdk-lib";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Topic } from "aws-cdk-lib/aws-sns";
import { EmailSubscription } from "aws-cdk-lib/aws-sns-subscriptions";
import { Construct } from "constructs";

interface AlarmSNSStackProps extends StackProps { emailAdress: string }

export class AlarmSNSStack extends Stack {
  constructor(scope: Construct, id: string, props: AlarmSNSStackProps) {
    super(scope, id, props);
    const topicName = 'topic'
    const snsTopic = new Topic(this, topicName, { displayName: topicName, topicName, fifo: false });
    snsTopic.addSubscription(new EmailSubscription(props.emailAdress));

    snsTopic.grantPublish(new NodejsFunction(this, 'publishLambda', {
      runtime: Runtime.NODEJS_18_X,
      entry: `../src/handler/invoke/events/sendMail.ts`,
      environment: { snsTopic: topicName },
    }))
    new CfnOutput(this, `sns-confirm-subscription`, {
      value: `aws sns confirm-subscription --topic-arn ${snsTopic.topicArn} --authenticate-on-unsubscribe true --region ${props.env?.region} --token xxxCopyAndPasteTokenfromMailxxx`,
    })
    new CfnOutput(this, `sns-list`, {
      value: `aws sns list-subscriptions-by-topic --topic-arn ${snsTopic.topicArn}`,
    })
    Aspects.of(this).add(new Tag('Stack', 'AlarmSNSStack'));
  }
}
src/handler/invoke/events/sendMail.ts
import { sendEMailMessage } from "@/domain/sns";
import { Handler } from "aws-lambda";

export const handler: Handler = async (event, context) => {
  console.log(event);
  const [__arn, __partition, __service, __region, accountId, __resourceId] = context.invokedFunctionArn.split(':');
  const envList = ['snsTopic', 'AWS_REGION'] as const;
  envList.forEach(k => { if (!process.env[k]) throw new Error(`${k} environment required`) });
  const processEnv = process.env as Record<typeof envList[number], string>;
  await sendEMailMessage({ account: accountId, region: processEnv.AWS_REGION, snsTopic: processEnv.snsTopic, subject: '件名テスト', message: '本文テスト' })
}
src/domain/sns/index.ts
import { PublishCommand, SNSClient, SubscribeCommand } from "@aws-sdk/client-sns";
let snsClient: SNSClient | null = null;
const getSNSClinent = (region: string): SNSClient => {
  if (snsClient) return snsClient;
  snsClient = new SNSClient({ region });
  return snsClient
}

const sendEMailMessage = async (props: { region: string; account: string; snsTopic: string, subject: string, message: string }) => {

  const params = {
    TopicArn: `arn:aws:sns:${props.region}:${props.account}:${props.snsTopic}`,
    Subject: props.subject,
    Message: props.message
  };

  const snsClient = getSNSClinent(props.region)
  try {
    const data = await snsClient.send(new PublishCommand(params));
    console.log("Success.", data);
    return data;
  } catch (err) {
    console.error("Error", err);
    throw err;
  }

}
export { sendEMailMessage };

lambda実施前にsubscriptionの設定

デプロイ直後にaws sns list-subscriptions-by-topic --topic-arn arn:aws:sns:ap-northeast-1:0000000000:topicを実行すると下記の結果が得られる。

{
    "Subscriptions": [
        {
            "SubscriptionArn": "PendingConfirmation",
            "Owner": "0000000000",
            "Protocol": "email",
            "Endpoint": "hoge@gmail.com",
            "TopicArn": "arn:aws:sns:ap-northeast-1:0000000000:topic"
        }
    ]
}

Amazon SNS メール通知の「unsubscribe」リンクを無効化するを参考に、確認メールのリンクに含まれていたトークンから承認を行う。

image.png

image.png

リンクをコピーしたアドレス内に、下記のようなトークンが含まれているのでこれをつかう。
image.png

その後、aws sns list-subscriptions-by-topic --topic-arn arn:aws:sns:ap-northeast-1:0000000000:topicを実行すると下記の結果が得られる。

{
    "Subscriptions": [
        {
            "SubscriptionArn": "arn:aws:sns:ap-northeast-1:0000000000:topic:11111111-xxxx-xxxx-xxxx-777xxx777xxx",
            "Owner": "0000000000",
            "Protocol": "email",
            "Endpoint": "hoge@gmail.com",
            "TopicArn": "arn:aws:sns:ap-northeast-1:0000000000:topic"
        }
    ]
}

この状態で、コンソールからLambdaを実行し、メールが届くことを確認できた。
GMailだと、サブスクリプションの確認メールは通常のフォルダだが、その後の通知メールはプロモーションフォルダに届いていた。

image.png

参考

デベロッパーガイド Amazon SNS メッセージの発行
誰かサブスクリプション解除した?を無くすために Amazon SNS によるメール通知の停止(Unsubscribe)リンクを無効化してみた

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?