Initial implementation of Azure Communication Service transport
Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>
This commit is contained in:
@@ -83,6 +83,18 @@ export interface Config {
|
||||
| {
|
||||
/** Only for debugging, disables the actual sending of emails */
|
||||
transport: 'stream';
|
||||
}
|
||||
| {
|
||||
transport: 'azure';
|
||||
/**
|
||||
* Azure Communication Services endpoint
|
||||
*/
|
||||
endpoint: string;
|
||||
/**
|
||||
* Optional Azure Communication Services access key
|
||||
* @visibility secret
|
||||
*/
|
||||
accessKey?: string;
|
||||
};
|
||||
/**
|
||||
* Sender email address
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-ses": "^3.550.0",
|
||||
"@aws-sdk/types": "^3.347.0",
|
||||
"@azure/communication-email": "^1.0.0",
|
||||
"@azure/identity": "^4.0.0",
|
||||
"@backstage/backend-plugin-api": "workspace:^",
|
||||
"@backstage/catalog-client": "workspace:^",
|
||||
"@backstage/catalog-model": "workspace:^",
|
||||
|
||||
+3
@@ -32,6 +32,7 @@ import {
|
||||
NotificationProcessorFilters,
|
||||
} from '@backstage/plugin-notifications-common';
|
||||
import {
|
||||
createAzureTransport,
|
||||
createSendmailTransport,
|
||||
createSesTransport,
|
||||
createSmtpTransport,
|
||||
@@ -117,6 +118,8 @@ export class NotificationsEmailProcessor implements NotificationProcessor {
|
||||
this.transporter = createSendmailTransport(this.transportConfig);
|
||||
} else if (transport === 'stream') {
|
||||
this.transporter = createStreamTransport();
|
||||
} else if (transport === 'azure') {
|
||||
this.transporter = createAzureTransport(this.transportConfig);
|
||||
} else {
|
||||
throw new Error(`Unsupported transport: ${transport}`);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { createTransport } from 'nodemailer';
|
||||
import {
|
||||
EmailClient,
|
||||
EmailMessage,
|
||||
EmailRecipients,
|
||||
} from '@azure/communication-email';
|
||||
import { DefaultAzureCredential } from '@azure/identity';
|
||||
import { Config } from '@backstage/config';
|
||||
import MailMessage from 'nodemailer/lib/mailer/mail-message';
|
||||
|
||||
export const createAzureTransport = async (config: Config) => {
|
||||
const accessKey = config.getOptionalString('accessKey');
|
||||
const credentials =
|
||||
accessKey === undefined ? new DefaultAzureCredential() : { key: accessKey };
|
||||
const emailClient = new EmailClient(
|
||||
config.getString('endpoint'),
|
||||
credentials,
|
||||
);
|
||||
const transport = {
|
||||
name: 'azure',
|
||||
version: '1.0.0',
|
||||
send: async (
|
||||
mail: MailMessage,
|
||||
callback: (err: Error | null, info: {} | null) => Promise<void>,
|
||||
) => {
|
||||
const envelope = mail.data.envelope || mail.message.getEnvelope();
|
||||
const from =
|
||||
typeof envelope.from === 'string'
|
||||
? envelope.from
|
||||
: config.getString('senderAddress');
|
||||
const to =
|
||||
typeof envelope.to === 'string' ? [envelope.to] : envelope.to ?? [];
|
||||
const recipients: EmailRecipients = {
|
||||
to: to.map(address => ({ address })),
|
||||
};
|
||||
|
||||
const content = {
|
||||
subject: mail.message.getHeader('Subject'),
|
||||
html:
|
||||
typeof mail.data.html === 'string'
|
||||
? mail.data.html
|
||||
: mail.data.html?.toString('utf-8'),
|
||||
plainText:
|
||||
typeof mail.data.text === 'string'
|
||||
? mail.data.text
|
||||
: mail.data.text?.toString('utf-8') ?? 'No content',
|
||||
};
|
||||
|
||||
const emailMessage: EmailMessage = {
|
||||
senderAddress: from,
|
||||
recipients: recipients,
|
||||
content: content,
|
||||
};
|
||||
|
||||
try {
|
||||
const poller = await emailClient.beginSend(emailMessage);
|
||||
const response = await poller.pollUntilDone();
|
||||
callback(null, response);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
callback(error, null);
|
||||
}
|
||||
},
|
||||
};
|
||||
return createTransport(transport);
|
||||
};
|
||||
@@ -17,3 +17,4 @@ export { createSmtpTransport } from './smtp';
|
||||
export { createSesTransport } from './ses';
|
||||
export { createSendmailTransport } from './sendmail';
|
||||
export { createStreamTransport } from './stream';
|
||||
export { createAzureTransport } from './azure';
|
||||
|
||||
@@ -1656,18 +1656,50 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@azure/core-auth@npm:^1.4.0, @azure/core-auth@npm:^1.5.0":
|
||||
version: 1.5.0
|
||||
resolution: "@azure/core-auth@npm:1.5.0"
|
||||
"@azure/communication-common@npm:^2.2.0":
|
||||
version: 2.3.1
|
||||
resolution: "@azure/communication-common@npm:2.3.1"
|
||||
dependencies:
|
||||
"@azure/abort-controller": ^1.0.0
|
||||
"@azure/core-util": ^1.1.0
|
||||
"@azure/core-auth": ^1.3.0
|
||||
"@azure/core-rest-pipeline": ^1.3.2
|
||||
"@azure/core-tracing": ^1.0.0
|
||||
"@azure/core-util": ^1.0.0
|
||||
events: ^3.0.0
|
||||
jwt-decode: ^4.0.0
|
||||
tslib: ^2.2.0
|
||||
checksum: 11c5ba072902693435dc2930e2fdfe2ff34836f4c2d6c87c6ac0566d48dc49157ebf49f4478cd3784dc0c4d57b502d3a12d74ea29f416725204a6e1aa937ef78
|
||||
checksum: de01172479bd0d498bccfd9906e9be7d57cf2b4c58159f140e573fd940c537fe0eba8d9fa8ee63469cb5c9f0c8d70bcac7afb330b514b4097a49df746367a255
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@azure/core-client@npm:^1.3.0, @azure/core-client@npm:^1.6.2, @azure/core-client@npm:^1.9.2":
|
||||
"@azure/communication-email@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "@azure/communication-email@npm:1.0.0"
|
||||
dependencies:
|
||||
"@azure/communication-common": ^2.2.0
|
||||
"@azure/core-auth": ^1.3.0
|
||||
"@azure/core-client": ^1.3.2
|
||||
"@azure/core-lro": ^2.5.0
|
||||
"@azure/core-rest-pipeline": ^1.8.0
|
||||
"@azure/logger": ^1.0.0
|
||||
tslib: ^1.9.3
|
||||
uuid: ^8.3.2
|
||||
checksum: d939c729b303bc1bf7272b7f54850114f3cc90760cc0f796bbc8e01cd2834d0b28b33bd27b9ce590db691df94fbc23b10e39fa3c5d82e4b000a523616b5f12ef
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@azure/core-auth@npm:^1.3.0, @azure/core-auth@npm:^1.4.0, @azure/core-auth@npm:^1.5.0, @azure/core-auth@npm:^1.8.0":
|
||||
version: 1.9.0
|
||||
resolution: "@azure/core-auth@npm:1.9.0"
|
||||
dependencies:
|
||||
"@azure/abort-controller": ^2.0.0
|
||||
"@azure/core-util": ^1.11.0
|
||||
tslib: ^2.6.2
|
||||
checksum: 4050112188db093c5e01caca0175708c767054c0cea4202430ff43ee42a16430235752ccc0002caea1796c8f01b4f6369c878762bf4c1b2f61af1b7ac13182fc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@azure/core-client@npm:^1.3.0, @azure/core-client@npm:^1.3.2, @azure/core-client@npm:^1.6.2, @azure/core-client@npm:^1.9.2":
|
||||
version: 1.9.2
|
||||
resolution: "@azure/core-client@npm:1.9.2"
|
||||
dependencies:
|
||||
@@ -1693,15 +1725,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@azure/core-lro@npm:^2.2.0":
|
||||
version: 2.5.4
|
||||
resolution: "@azure/core-lro@npm:2.5.4"
|
||||
"@azure/core-lro@npm:^2.2.0, @azure/core-lro@npm:^2.5.0":
|
||||
version: 2.7.2
|
||||
resolution: "@azure/core-lro@npm:2.7.2"
|
||||
dependencies:
|
||||
"@azure/abort-controller": ^1.0.0
|
||||
"@azure/abort-controller": ^2.0.0
|
||||
"@azure/core-util": ^1.2.0
|
||||
"@azure/logger": ^1.0.0
|
||||
tslib: ^2.2.0
|
||||
checksum: f048b99850e8497b557cf661c2f8a384ea1227de6ea0c0e1436653851c3932e28a05056a380f7c20ebc51e4c6d7bd15d7dfabc6ecca80eddb9dc3e3339df9519
|
||||
tslib: ^2.6.2
|
||||
checksum: dc2e5bbb004a86704bcf584422cd099b7a6beef57ce6501afacced65f4f3b5fbba57a2439f701687237867552a661fd6568f8b3c9e3eacdfd9039004772f85b0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1714,19 +1746,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@azure/core-rest-pipeline@npm:^1.1.0, @azure/core-rest-pipeline@npm:^1.10.1, @azure/core-rest-pipeline@npm:^1.3.0, @azure/core-rest-pipeline@npm:^1.9.1":
|
||||
version: 1.16.1
|
||||
resolution: "@azure/core-rest-pipeline@npm:1.16.1"
|
||||
"@azure/core-rest-pipeline@npm:^1.1.0, @azure/core-rest-pipeline@npm:^1.10.1, @azure/core-rest-pipeline@npm:^1.3.0, @azure/core-rest-pipeline@npm:^1.3.2, @azure/core-rest-pipeline@npm:^1.8.0, @azure/core-rest-pipeline@npm:^1.9.1":
|
||||
version: 1.19.0
|
||||
resolution: "@azure/core-rest-pipeline@npm:1.19.0"
|
||||
dependencies:
|
||||
"@azure/abort-controller": ^2.0.0
|
||||
"@azure/core-auth": ^1.4.0
|
||||
"@azure/core-auth": ^1.8.0
|
||||
"@azure/core-tracing": ^1.0.1
|
||||
"@azure/core-util": ^1.9.0
|
||||
"@azure/core-util": ^1.11.0
|
||||
"@azure/logger": ^1.0.0
|
||||
http-proxy-agent: ^7.0.0
|
||||
https-proxy-agent: ^7.0.0
|
||||
tslib: ^2.6.2
|
||||
checksum: ab2c5b715c4ebb9f6554f12d8e804833be29db0f23868adc092f4841aa8c7f140a6821dbcd9fa046bfb31e435085f171a87dab3f97d851cf9a62127d042fa75e
|
||||
checksum: e8d7631152d7af27b949f3da792a22a92a633b5744604f90e02e56e0b888e031f15f5d3384d7ca65ae851492ad0e33972f000b99600b081ceb0eb66e294454c1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1739,13 +1771,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@azure/core-util@npm:^1.1.0, @azure/core-util@npm:^1.2.0, @azure/core-util@npm:^1.3.0, @azure/core-util@npm:^1.6.1, @azure/core-util@npm:^1.9.0":
|
||||
version: 1.9.0
|
||||
resolution: "@azure/core-util@npm:1.9.0"
|
||||
"@azure/core-util@npm:^1.0.0, @azure/core-util@npm:^1.11.0, @azure/core-util@npm:^1.2.0, @azure/core-util@npm:^1.3.0, @azure/core-util@npm:^1.6.1":
|
||||
version: 1.11.0
|
||||
resolution: "@azure/core-util@npm:1.11.0"
|
||||
dependencies:
|
||||
"@azure/abort-controller": ^2.0.0
|
||||
tslib: ^2.6.2
|
||||
checksum: 9246dc5bd246e7b94883ea8130fce04e2f22abd1e94afcff7a3e92a4c2da5e9b382dbf89a606b21d70bc8b01c7c89c84e803ca9da27f78d87f72bdff91ec7380
|
||||
checksum: 91e3ec329d9eddaa66be5efb1785dad68dcb48dd779fca36e39db041673230510158ff5ca9ccef9f19c3e4d8e9af29f66a367cfc31a7b94d2541f80ef94ec797
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -7042,6 +7074,8 @@ __metadata:
|
||||
dependencies:
|
||||
"@aws-sdk/client-ses": ^3.550.0
|
||||
"@aws-sdk/types": ^3.347.0
|
||||
"@azure/communication-email": ^1.0.0
|
||||
"@azure/identity": ^4.0.0
|
||||
"@backstage/backend-plugin-api": "workspace:^"
|
||||
"@backstage/backend-test-utils": "workspace:^"
|
||||
"@backstage/catalog-client": "workspace:^"
|
||||
@@ -34548,6 +34582,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jwt-decode@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "jwt-decode@npm:4.0.0"
|
||||
checksum: 390e2edcb31a92e86c8cbdd1edeea4c0d62acd371f8a8f0a8878e499390c0ecf4c658b365c4e941e4ef37d0170e4ca650aaa49f99a45c0b9695a235b210154b0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"keygrip@npm:~1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "keygrip@npm:1.1.0"
|
||||
@@ -45769,7 +45810,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tslib@npm:^1.11.1, tslib@npm:^1.14.1, tslib@npm:^1.8.1, tslib@npm:^1.9.0":
|
||||
"tslib@npm:^1.11.1, tslib@npm:^1.14.1, tslib@npm:^1.8.1, tslib@npm:^1.9.0, tslib@npm:^1.9.3":
|
||||
version: 1.14.1
|
||||
resolution: "tslib@npm:1.14.1"
|
||||
checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd
|
||||
|
||||
Reference in New Issue
Block a user