Create new Pinpoint application and add email identity and channel if aren't presented
Service limitations
Quotas: https://docs.aws.amazon.com/pinpoint/latest/developerguide/quotas.html
Configuration is done via AWS-SDK instead of CDK for support multi-tenant, also could be configured via CDK for Pinpoint and Email Channel , but identity creation should be implemented separately via console or SDK predeploy script.
Configuring the service
aws-tag.model.ts
export interface AwsTag {
Key: string;
Value: string;
}
organization.model.ts
import { Pinpoint, PinpointEmail, STS } from 'aws-sdk';
import { IdentityInfo } from 'aws-sdk/clients/pinpointemail';
import { AwsTag } from './aws-tag.model';
export class CliOrganization {
private readonly awsPinpoint = new Pinpoint();
private readonly awsPinpointEmail = new PinpointEmail();
private readonly awsSts = new STS();
// Parameters could be provided by config structure
constructor(
private orgId: string,
private email: string
) {}
public async createOrganization(envType: string, env: string, stackName: string) {
const tags = { organization: this.orgId }; // Any tags could be provided here
const tagsArray = this.getTagsArray(tags);
const awsAccountId = await this.getAccountId();
console.log('[*] creating pinpoint app');
const pinpointApp = await this.getOrCreatePinpointApp(this.orgId, tags);
console.log(`[*] created pinpoint app : ${pinpointApp.Id}`);
console.log('[*] creating email identity');
const identity = await this.getOrCreateEmailIdentity(this.email, tagsArray);
console.log(`[*] created email identity : ${identity.IdentityName}`);
console.log('[*] getting email arn');
const identityArn = `arn:aws:ses:${process.env.AWS_REGION}:${awsAccountId}:identity/${identity.IdentityName}`;
console.log(`[*] got email arn : ${identityArn}`);
console.log('[*] creating email channel');
const emailChannelRes = await this.awsPinpoint
.updateEmailChannel({
ApplicationId: pinpointApp.Id,
EmailChannelRequest: {
Identity: identityArn,
FromAddress: this.email,
Enabled: true,
},
})
.promise();
console.log(`[*] created email channel : ${emailChannelRes.EmailChannelResponse.Id}`);
}
public async getAccountId(): Promise<string> {
const callerIdentityRes = await this.awsSts.getCallerIdentity().promise();
return callerIdentityRes.Account as string;
}
private async getOrCreateEmailIdentity(email: string, tagsArray: AwsTag[]): Promise<IdentityInfo> {
let token: string | undefined;
do {
const resList = await this.awsPinpointEmail
.listEmailIdentities({
NextToken: token,
})
.promise();
token = resList.NextToken;
const existing = resList?.EmailIdentities?.find(identity => identity.IdentityName === email);
if (existing) {
return existing;
}
} while (token);
const res = await this.awsPinpointEmail
.createEmailIdentity({
EmailIdentity: email,
Tags: tagsArray,
})
.promise();
return res;
}
private async getOrCreatePinpointApp(
orgId: string,
tags: { organization: string },
): Promise<Pinpoint.ApplicationResponse> {
const app = await this.getPinpointApp(orgId);
if (app) {
return app;
}
const res = await this.awsPinpoint
.createApp({
CreateApplicationRequest: {
tags,
Name: `${orgId}`,
},
})
.promise();
return res.ApplicationResponse;
}
private getTagsArray(tags: { [key: string]: string }): AwsTag[] {
return Object.keys(tags).map(key => ({ Key: key, Value: tags[key] }));
}
private async getPinpointApp(orgId: string): Promise<Pinpoint.ApplicationResponse | undefined> {
let token: string | undefined;
do {
const res = await this.awsPinpoint
.getApps({
Token: token,
})
.promise();
token = res.ApplicationsResponse.NextToken;
const app = res?.ApplicationsResponse?.Item?.find(item => item.Name === orgId);
if (app) {
return app;
}
} while (token);
return;
}
}
cli.ts
#!/usr/bin/env node
import * as yargs from 'yargs';
import { CliOrganization } from './organization.models';
// Parameters could be provided as config file
const cliOrganization = new CliOrganization('orgId','test@email.com');
// this creates a cmd executable script. no need to use a variable to store an output
// tslint:disable-next-line: no-unused-expression
yargs
.command(
'organization:create',
'Creates organization',
() => null,
async () =>
await cliOrganization.createOrganization(),
)
.demandCommand().argv;
package.json
...
"scripts": {
"cli": "cross-env-shell AWS_SDK_LOAD_CONFIG=1 NODE_OPTIONS=--max_old_space_size=4096 cross-env-shell npx ts-node --compiler ttypescript --project tsconfig.json ./bin/cli/cli.ts",
...
}
...
Deploy
npm run cli organization:create
Using the service
See example here
Comments
0 comments
Please sign in to leave a comment.