From d627f03e8e1b59cd0f8d60b5d518e72bd1c7b1cd Mon Sep 17 00:00:00 2001 From: veyselboybay Date: Wed, 5 Jun 2024 14:17:54 -0400 Subject: [PATCH] Implemented the emailing service --- README.md | 16 +++--- Server/index.js | 12 ---- Server/package-lock.json | 115 ++++++++++++++++++++++++++++++++++++++ Server/package.json | 1 + Server/utils/sendEmail.js | 63 ++++++++++----------- 5 files changed, 153 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index ff5190652..daf504923 100644 --- a/README.md +++ b/README.md @@ -63,14 +63,14 @@ BlueWave uptime monitoring application Configure the server with the following environmental variables -| ENV Variable Name | Required/Optional | Type | Description | Accepted Values | -| -------------------- | ----------------- | --------- | ----------------------------------------------------- | ------------------- | -| JWT_SECRET | Required | `string` | JWT secret | | -| DB_TYPE | Optional | `string` | Specify DB to use | `MongoDB \| FakeDB` | -| DB_CONNECTION_STRING | Required | `string` | Specifies URL for MongoDB Database | | -| PORT | Optional | `integer` | Specifies Port for Server | | -| MAILERSEND_API_KEY | Required | `string` | Specifies API KEY for MailerSend service | | -| SYSTEM_EMAIL_ADDRESS | Required | `string` | Specifies System email to be used in emailing service | | +| ENV Variable Name | Required/Optional | Type | Description | Accepted Values | +| -------------------- | ----------------- | --------- | ------------------------------------------------------------------------------------------- | ------------------- | +| JWT_SECRET | Required | `string` | JWT secret | | +| DB_TYPE | Optional | `string` | Specify DB to use | `MongoDB \| FakeDB` | +| DB_CONNECTION_STRING | Required | `string` | Specifies URL for MongoDB Database | | +| PORT | Optional | `integer` | Specifies Port for Server | | +| SENDGRID_API_KEY | Required | `string` | Specifies API KEY for SendGrid email service | | +| SYSTEM_EMAIL_ADDRESS | Required | `string` | Specifies System email to be used in emailing service, must be a verified email by sendgrid | | --- diff --git a/Server/index.js b/Server/index.js index d194606f6..f1b8c1a63 100644 --- a/Server/index.js +++ b/Server/index.js @@ -11,8 +11,6 @@ const logger = require("./utils/logger"); const { verifyJWT } = require("./middleware/verifyJWT"); const { handleErrors } = require("./middleware/handleErrors"); -// const { sendEmail } = require('./utils/sendEmail') - // ************************** // Here is where we can swap out DBs easily. Spin up a mongoDB instance and try it out. // Simply comment out the FakeDB and uncomment the MongoDB or vice versa. @@ -35,11 +33,6 @@ const db = DB_TYPE[process.env.DB_TYPE] ? DB_TYPE[process.env.DB_TYPE]() : require("./db/FakeDb"); -/** - * NOTES - * Email Service will be added - * Logger Service will be added (Winston or similar) - */ const app = express(); @@ -67,11 +60,6 @@ app.use("/api/v1/monitors", monitorRouter); app.use("/api/v1/checks", verifyJWT, checkRouter); app.use("/api/v1/alerts", verifyJWT, alertRouter); -// Testing email service -// app.use('/sendEmail', async (req, res) => { -// const response = sendEmail(['veysel.boybay@bluewavelabs.ca'], 'Testing email service', '

Testing Bluewavelabs

'); -// console.log(response); -// }) //health check app.use("/api/v1/healthy", (req, res) => { diff --git a/Server/package-lock.json b/Server/package-lock.json index 9ee830ebd..c8c366248 100644 --- a/Server/package-lock.json +++ b/Server/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "@sendgrid/mail": "^8.1.3", "bcrypt": "^5.1.1", "cors": "^2.8.5", "dotenv": "^16.4.5", @@ -96,6 +97,41 @@ "sparse-bitfield": "^3.0.3" } }, + "node_modules/@sendgrid/client": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-8.1.3.tgz", + "integrity": "sha512-mRwTticRZIdUTsnyzvlK6dMu3jni9ci9J+dW/6fMMFpGRAJdCJlivFVYQvqk8kRS3RnFzS7sf6BSmhLl1ldDhA==", + "dependencies": { + "@sendgrid/helpers": "^8.0.0", + "axios": "^1.6.8" + }, + "engines": { + "node": ">=12.*" + } + }, + "node_modules/@sendgrid/helpers": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-8.0.0.tgz", + "integrity": "sha512-Ze7WuW2Xzy5GT5WRx+yEv89fsg/pgy3T1E3FS0QEx0/VvRmigMZ5qyVGhJz4SxomegDkzXv/i0aFPpHKN8qdAA==", + "dependencies": { + "deepmerge": "^4.2.2" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/@sendgrid/mail": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-8.1.3.tgz", + "integrity": "sha512-Wg5iKSUOER83/cfY6rbPa+o3ChnYzWwv1OcsR8gCV8SKi+sUPIMroildimlnb72DBkQxcbylxng1W7f0RIX7MQ==", + "dependencies": { + "@sendgrid/client": "^8.1.3", + "@sendgrid/helpers": "^8.0.0" + }, + "engines": { + "node": ">=12.*" + } + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -229,6 +265,21 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -422,6 +473,17 @@ "text-hex": "1.0.x" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -484,6 +546,14 @@ "ms": "2.0.0" } }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -500,6 +570,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -689,6 +767,38 @@ "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1703,6 +1813,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", diff --git a/Server/package.json b/Server/package.json index 60777f7a5..9b5f08737 100644 --- a/Server/package.json +++ b/Server/package.json @@ -11,6 +11,7 @@ "author": "", "license": "ISC", "dependencies": { + "@sendgrid/mail": "^8.1.3", "bcrypt": "^5.1.1", "cors": "^2.8.5", "dotenv": "^16.4.5", diff --git a/Server/utils/sendEmail.js b/Server/utils/sendEmail.js index 712a651bd..488cd9170 100644 --- a/Server/utils/sendEmail.js +++ b/Server/utils/sendEmail.js @@ -1,43 +1,38 @@ -const { MailerSend, EmailParams, Sender, Recipient } = require('mailersend') -const logger = require('../utils/logger') - - -const mailersend = new MailerSend({ - apiKey: process.env.MAILERSEND_API_KEY, -}) +const sgMail = require('@sendgrid/mail') +const logger = require('./logger') +const dotenv = require('dotenv') +dotenv.config({path:__dirname+'/../.env'}) +sgMail.setApiKey(process.env.SENDGRID_API_KEY) +const SERVICE_NAME = 'Email_Service'; /** + * @async * @function - * @param {[string]} receivers - takes an array of strings - * @param {string} subject - takes a single string - * @param {string} contentHTML - takes a single string that contains HTML - * @returns {JSON} - * @example - * sendEmail(['veysel@bluewavelabs.ca','alex@bluewavelabs.ca','monzer@bluewavelabs.ca'],'Testing Email Servide','

BlueWaveLabs

') + * @param {[String]} receivers - takes an array of strings + * @param {String} subject - takes a single string + * @param {String} contentHTML - takes a single string that contains HTML + * @param {String} contentText - takes a string to be used if contentHTML is not compatible + * @example + * await sendEmail(['veysel@bluewavelabs.ca','alex@bluewavelabs.ca'],'Testing Email Service','

BlueWaveLabs

','Testing Email Service') */ -// TODO: from email should be in .env file -const sendEmail = async (receivers,subject,contentHTML) => { - // Sender - const from = process.env.SYSTEM_EMAIL_ADDRESS; - const sender = new Sender(from); - // receivers - let recipients = [] - receivers.map(email => recipients.push(new Recipient(email))); - // Set params - const emailParams = new EmailParams() - .setFrom(sender) - .setTo(recipients) - .setSubject(subject) - .setHtml(contentHTML); - +const sendEmail = async (receivers,subject, contentHTML, contentText = null ) => { + const msg = { + to: receivers, + from: { + name: 'Uptime System', + email: process.env.SYSTEM_EMAIL_ADDRESS // must be verified email by sendgrid + }, + subject: subject, + text: contentText || contentHTML, + html: contentHTML, + } try { - const response = await mailersend.email.send(emailParams); - logger.info("Email sent to receivers!",{"service":"Email"}) - return response; - + await sgMail.send(msg); + logger.info(`Emails sent to receivers:${receivers} with the subject:${subject}`,{service:SERVICE_NAME}) } catch (error) { - logger.error(error.body,{"service":"email"}) - console.log(error.body) + logger.error(`Sending Email action failed, ERROR:${error}`, { service: SERVICE_NAME }); } } + + module.exports = {sendEmail} \ No newline at end of file