diff --git a/apps/nestjs-api/src/email/lib/email/email.js b/apps/nestjs-api/src/email/lib/email/email.js index 6aeb1e221..93a00395c 100644 --- a/apps/nestjs-api/src/email/lib/email/email.js +++ b/apps/nestjs-api/src/email/lib/email/email.js @@ -4,26 +4,44 @@ import { buildFrontendUrl } from '../build-frontend-url' const Rx = require('rxjs') const mjml2html = require('mjml') -const nodemailer = require('nodemailer') const fs = require('fs') const path = require('path') +const { EmailClient } = require('@azure/communication-email') -const transporter = nodemailer.createTransport({ - host: 'smtp.googlemail.com', - port: 465, - secure: true, - auth: { - user: 'career@redi-school.org', - pass: process.env.NX_GWORKSPACE_EMAIL_PASSWORD, - }, -}) +const connectionString = process.env.AZURE_COMMUNICATION_CONNECTION_STRING +if (!connectionString) + throw new Error('AZURE_COMMUNICATION_CONNECTION_STRING env var not set') +const emailClient = new EmailClient(connectionString) + +const formatRecipients = (emailAddresses) => { + if (!emailAddresses) return [] + if (typeof emailAddresses === 'string') return [{ address: emailAddresses }] + return emailAddresses.map((email) => ({ address: email })) +} const isProductionOrDemonstration = () => ['production', 'demonstration', 'staging'].includes(process.env.NODE_ENV) -export const sendMjmlEmail = Rx.bindNodeCallback( - transporter.sendMail.bind(transporter) -) +export const sendMjmlEmail = (emailParams) => + Rx.from( + (async function iifeSendEmail() { + const emailMessage = { + senderAddress: 'career@redi-school.org', + content: { + subject: emailParams.subject, + html: emailParams.html, + }, + recipients: { + to: formatRecipients(emailParams.to), + bcc: formatRecipients(emailParams.bcc), + }, + } + + const poller = await emailClient.beginSend(emailMessage) + const result = await poller.pollUntilDone() + return result + })() + ) // TODO: I'm a duplicate of getSenderDetails in apps/api/lib/email/email.js, keep me in sync const getSenderDetails = (rediLocation) => { @@ -32,7 +50,7 @@ const getSenderDetails = (rediLocation) => { ? 'ReDI Malmö Team' : 'ReDI Talent Success Team' const senderEmail = isMalmoLocation - ? 'career@redi-school.org' // TODO: set back to career-sweden when we send email via Azure + ? 'career-sweden@redi-school.org' // TODO: set back to career-sweden when we send email via Azure : 'career@redi-school.org' return { senderName, senderEmail } } diff --git a/loopback-standalone/lib/email/email.js b/loopback-standalone/lib/email/email.js index fb792b2a8..b79523467 100644 --- a/loopback-standalone/lib/email/email.js +++ b/loopback-standalone/lib/email/email.js @@ -2,29 +2,47 @@ const Rx = require('rxjs') const mjml2html = require('mjml') -const nodemailer = require('nodemailer') const fs = require('fs') const path = require('path') +const { EmailClient } = require('@azure/communication-email') const { buildFrontendUrl } = require('../build-frontend-url') const { buildBackendUrl } = require('../build-backend-url') -const transporter = nodemailer.createTransport({ - host: 'smtp.googlemail.com', - port: 465, - secure: true, - auth: { - user: 'career@redi-school.org', - pass: process.env.NX_GWORKSPACE_EMAIL_PASSWORD, - }, -}) +const connectionString = process.env.AZURE_COMMUNICATION_CONNECTION_STRING +if (!connectionString) + throw new Error('AZURE_COMMUNICATION_CONNECTION_STRING env var not set') +const emailClient = new EmailClient(connectionString) + +const formatRecipients = (emailAddresses) => { + if (!emailAddresses) return [] + if (typeof emailAddresses === 'string') return [{ address: emailAddresses }] + return emailAddresses.map((email) => ({ address: email })) +} const isProductionOrDemonstration = () => ['production', 'demonstration', 'staging'].includes(process.env.NODE_ENV) -const sendMjmlEmail = Rx.bindNodeCallback( - transporter.sendMail.bind(transporter) -) +export const sendMjmlEmail = (emailParams) => + Rx.from( + (async function iifeSendEmail() { + const emailMessage = { + senderAddress: 'career@redi-school.org', + content: { + subject: emailParams.subject, + html: emailParams.html, + }, + recipients: { + to: formatRecipients(emailParams.to), + bcc: formatRecipients(emailParams.bcc), + }, + } + + const poller = await emailClient.beginSend(emailMessage) + const result = await poller.pollUntilDone() + return result + })() + ) // TODO: I'm a duplicate of getSenderDetails in apps/nestjs-api/src/email/lib/email/email.js, keep me in sync const getSenderDetails = (rediLocation) => { diff --git a/package.json b/package.json index 0d96f25c1..84d828422 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ }, "private": true, "dependencies": { + "@azure/communication-email": "^1.0.0", "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@formbricks/js": "^2.1.0", diff --git a/yarn.lock b/yarn.lock index 34a0ab6d6..2444d5ed3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -164,6 +164,116 @@ dependencies: xss "^1.0.8" +"@azure/abort-controller@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.1.0.tgz#788ee78457a55af8a1ad342acb182383d2119249" + integrity sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw== + dependencies: + tslib "^2.2.0" + +"@azure/abort-controller@^2.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-2.1.2.tgz#42fe0ccab23841d9905812c58f1082d27784566d" + integrity sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA== + dependencies: + tslib "^2.6.2" + +"@azure/communication-common@^2.2.0": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@azure/communication-common/-/communication-common-2.3.1.tgz#2a847a2d9c7e7b479db4f90e0a46484cd86179f7" + integrity sha512-6ZQt20iMZbyckQn4m1TDwiDv3Fzyt1h4lnQ1szBBns2x3VQY9XHbnskPtvUdwK/HT+c/1PoUwof3toy1AIznbQ== + dependencies: + "@azure/abort-controller" "^1.0.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" + +"@azure/communication-email@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@azure/communication-email/-/communication-email-1.0.0.tgz#7a15d0438e2438aba1953202890d3908b49f41b3" + integrity sha512-aY/qE3u4gadd6I895WOJPXrbKaPqeFDxGOK5xgAAqHkqNadI+hCp/D59q5Kfcj5Qcxal6mLm1GwZ1Cka0x4KZw== + 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" + +"@azure/core-auth@^1.3.0", "@azure/core-auth@^1.4.0", "@azure/core-auth@^1.8.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@azure/core-auth/-/core-auth-1.9.0.tgz#ac725b03fabe3c892371065ee9e2041bee0fd1ac" + integrity sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-util" "^1.11.0" + tslib "^2.6.2" + +"@azure/core-client@^1.3.2": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@azure/core-client/-/core-client-1.9.2.tgz#6fc69cee2816883ab6c5cdd653ee4f2ff9774f74" + integrity sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.4.0" + "@azure/core-rest-pipeline" "^1.9.1" + "@azure/core-tracing" "^1.0.0" + "@azure/core-util" "^1.6.1" + "@azure/logger" "^1.0.0" + tslib "^2.6.2" + +"@azure/core-lro@^2.5.0": + version "2.7.2" + resolved "https://registry.yarnpkg.com/@azure/core-lro/-/core-lro-2.7.2.tgz#787105027a20e45c77651a98b01a4d3b01b75a08" + integrity sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-util" "^1.2.0" + "@azure/logger" "^1.0.0" + tslib "^2.6.2" + +"@azure/core-rest-pipeline@^1.3.2", "@azure/core-rest-pipeline@^1.8.0", "@azure/core-rest-pipeline@^1.9.1": + version "1.19.0" + resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.19.0.tgz#4cc60d3f2ee68cf0ef379851b4ed175f7932c8c5" + integrity sha512-bM3308LRyg5g7r3Twprtqww0R/r7+GyVxj4BafcmVPo4WQoGt5JXuaqxHEFjw2o3rvFZcUPiqJMg6WuvEEeVUA== + dependencies: + "@azure/abort-controller" "^2.0.0" + "@azure/core-auth" "^1.8.0" + "@azure/core-tracing" "^1.0.1" + "@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" + +"@azure/core-tracing@^1.0.0", "@azure/core-tracing@^1.0.1": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@azure/core-tracing/-/core-tracing-1.2.0.tgz#7be5d53c3522d639cf19042cbcdb19f71bc35ab2" + integrity sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg== + dependencies: + tslib "^2.6.2" + +"@azure/core-util@^1.0.0", "@azure/core-util@^1.11.0", "@azure/core-util@^1.2.0", "@azure/core-util@^1.6.1": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@azure/core-util/-/core-util-1.11.0.tgz#f530fc67e738aea872fbdd1cc8416e70219fada7" + integrity sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g== + dependencies: + "@azure/abort-controller" "^2.0.0" + tslib "^2.6.2" + +"@azure/logger@^1.0.0": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@azure/logger/-/logger-1.1.4.tgz#223cbf2b424dfa66478ce9a4f575f59c6f379768" + integrity sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ== + dependencies: + tslib "^2.6.2" + "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz" @@ -6281,6 +6391,11 @@ agent-base@6: dependencies: debug "4" +agent-base@^7.1.0, agent-base@^7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" + integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" @@ -12334,6 +12449,14 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" +http-proxy-agent@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + http-proxy-middleware@^2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.4.tgz" @@ -12430,6 +12553,14 @@ https-proxy-agent@^5.0.1: agent-base "6" debug "4" +https-proxy-agent@^7.0.0: + version "7.0.6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== + dependencies: + agent-base "^7.1.2" + debug "4" + human-signals@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz" @@ -14395,6 +14526,11 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" +jwt-decode@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-4.0.0.tgz#2270352425fd413785b2faf11f6e755c5151bd4b" + integrity sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA== + keypress@~0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/keypress/-/keypress-0.2.1.tgz" @@ -21245,6 +21381,11 @@ tslib@^2, tslib@~2.4.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== +tslib@^2.6.2: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + tsutils@^3.17.1, tsutils@^3.21.0: version "3.21.0" resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz"