Skip to content
Permalink
Browse files
Send email campaign
  • Loading branch information
Johnny Lin committed Jun 11, 2020
1 parent 88498cd commit 6067925daf883477f706312e0dbf4fc0f99cd541
Show file tree
Hide file tree
Showing 7 changed files with 1,286 additions and 275 deletions.
@@ -15,6 +15,7 @@ const { ClientFile } = require("shared/models");
// Utilities
const { Database } = require("shared/utilities");
const { Email } = require("shared/utilities");
const { Secure } = require("shared/utilities");
const multer = require("multer");
const upload = multer({ dest : "../uploads" });
const aws = require("aws-sdk");
@@ -235,6 +236,49 @@ router.post("/delete-user-with-id",
.catch(error => { next(error); });
});

/*********************************************
*
* Generate Users
*
*********************************************/

router.post("/generate-users",
[
authenticate,
body("num")
.exists().withMessage("Missing num."),
validateCheck
],
(request, response, next) => {

var num = request.values.num;

Email.sendAdminAlert("ADMIN ACTION", "Generate Users By " + request.user.email);

let chain = Promise.resolve();
let count = 0;
for (var i = 0; i < num; i++) {
chain = chain
.then(() => {
count = count + 1;
var email = `success+${Secure.randomString(15)}@simulator.amazonses.com`;
Logger.info("Generating user #" + count + " email: " + email);
return User.createWithEmailAndPassword(email, "TestPass!123", false, null, true)
.then(user => {
return User.confirmEmail(user.emailConfirmCode, email);
})
.catch(error => {
Logger.error("error: " + JSON.stringify(error));
});
})
}

response.status(200).json({
message: "queued"
})

});

/*********************************************
*
* Upload and Modify Client
@@ -6,14 +6,27 @@ const authenticate = require("../middleware/authenticate.js");
const { body } = require("express-validator/check");
const validateCheck = require("../middleware/validate-check.js");

// Models
const { User, Campaign, CampaignEmail } = require("shared/models");

// Utilities
const { Email } = require("shared/utilities");
const { Email, Secure } = require("shared/utilities");
const nodemailer = require('nodemailer');
const aws = require("aws-sdk");
const transporter = nodemailer.createTransport({
SES: new aws.SES({
apiVersion: '2010-12-01'
}),
sendingRate: 13 // max 10 messages/second
});
const sqs = new aws.SQS();
const sts = new aws.STS();
const handlebars = require("handlebars");

// Constants
const ENVIRONMENT = process.env.ENVIRONMENT;
const DOMAIN = process.env.DOMAIN;
const AES_EMAIL_KEY = process.env.AES_EMAIL_KEY;
const ENVIRONMENT = process.env.ENVIRONMENT == "LOCAL" ? "DEV" : process.env.ENVIRONMENT;
const QUEUE_REGION = "us-east-1"
var accountId;

@@ -30,6 +43,7 @@ router.get("/email",
authenticate,
(request, response, next) => {
var bouncesAttributes;
var complaintAttributes;
return sts.getCallerIdentity().promise()
.then( result => {
accountId = result.Account;
@@ -46,13 +60,183 @@ authenticate,
}).promise()
})
.then( result => {
response.render("email",
complaintAttributes = result;
return Campaign.getAll()
})
.then( result => {
return response.render("email",
{
bounces: bouncesAttributes.Attributes.ApproximateNumberOfMessages,
complaints: result.Attributes.ApproximateNumberOfMessages
complaints: complaintAttributes.Attributes.ApproximateNumberOfMessages,
campaigns: result
});
})
.catch(error => { next(error); });
});

router.post("/campaign-stats",
[
authenticate,
body("id")
.exists().withMessage("Missing id."),
validateCheck
],
(request, response, next) => {

var id = request.values.id;

// Notify Admin
Email.sendAdminAlert("ADMIN ACTION", "Get Campaign Stats By " + request.user.email);

return Campaign.getStats(id)
.then( stats => {
return response.status(200).json(stats);
})
.catch(error => { next(error); });
});

router.post("/create-campaign",
[
authenticate,
body("name")
.exists().withMessage("Missing name."),
body("fromAddress")
.exists().withMessage("Missing fromAddress."),
body("subject")
.exists().withMessage("Missing subject."),
body("html")
.exists().withMessage("Missing html."),
body("plaintext")
.exists().withMessage("Missing plain."),
validateCheck
],
(request, response, next) => {

var name = request.values.name;
var fromAddress = request.values.fromAddress;
var subject = request.values.subject;
var html = request.values.html;
var plaintext = request.values.plaintext;

// Notify Admin
Email.sendAdminAlert("ADMIN ACTION", "Created Campaign By " + request.user.email);

return Campaign.create(name, fromAddress, subject, html, plaintext)
.then( info => {
return response.status(200).json({
message: "success"
});
})
.catch(error => { next(error); });
});

router.post("/send-single-email",
[
authenticate,
body("campaignId")
.exists().withMessage("Missing campaign ID."),
body("toAddress")
.exists().withMessage("Missing to."),
validateCheck
],
(request, response, next) => {

var campaignId = request.values.campaignId;
var toAddress = request.values.toAddress;

Email.sendAdminAlert("ADMIN ACTION", "Send Single Email By " + request.user.email);

var unsubscribeCode = "";
var campaign;

return User.getWithEmail(toAddress)
.catch( error => {
Logger.info("Error getting user but continuing: " + JSON.stringify(error))
})
.then( user => {
if (user) {
unsubscribeCode = user.newsletterUnsubscribeCode;
}
return Campaign.getById(campaignId);
})
.then( result => {
campaign = result;
unsubscribeLink = `https://${DOMAIN}/newsletter-unsubscribe?email=${toAddress}&code=${unsubscribeCode}`
let plaintext = campaign.plaintext + "\nUnsubscribe from future emails: " + unsubscribeLink;
let html = campaign.html + `<div style="width:100%; text-align:center; margin-bottom: 10px;"><a href="${unsubscribeLink}" style="font-size: 10.5px; text-decoration: underline; color: gray;">Unsubscribe</a></div>`;
return transporter.sendMail({
from: campaign.fromAddress,
to: toAddress,
subject: campaign.subject,
text: plaintext,
html: html
});
})
.then( info => {
response.status(200).json({
message: "success"
})
})
.catch(error => { next(error); });

});

router.post("/send-emails-to-campaign",
[
authenticate,
body("campaignId")
.exists().withMessage("Missing campaign ID."),
body("maxNum")
.exists().withMessage("Missing number of emails."),
validateCheck
],
(request, response, next) => {

var campaignId = request.values.campaignId;
var maxNum = request.values.maxNum;
var campaign;
var count = 0;
var successCount = 0;

Email.sendAdminAlert("ADMIN ACTION", "Send Emails To Campaign By " + request.user.email);

return Campaign.getById(campaignId)
.then( result => {
campaign = result;
Logger.info("getting unsent emails and marking as sent")
return CampaignEmail.getUnsentEmailsAndMarkAsSent(campaignId, maxNum);
})
.then( campaignEmails => {
response.status(200).json({
message: "queuing " + campaignEmails.length + " campaign emails"
})
campaignEmails.forEach(campaignEmail => {
count = count + 1;
Logger.info("queueing email #" + count)
var email = Secure.aesDecrypt(campaignEmail.emailEncrypted, AES_EMAIL_KEY);
unsubscribeLink = `https://${DOMAIN}/newsletter-unsubscribe?email=${email}&code=${campaignEmail.unsubscribeCode}`
let plaintext = campaign.plaintext + "\nUnsubscribe from future emails: " + unsubscribeLink;
let html = campaign.html + `<div style="width:100%; text-align:center; margin-bottom: 10px;"><a href="${unsubscribeLink}" style="font-size: 10.5px; text-decoration: underline; color: gray;">Unsubscribe</a></div>`;
transporter.sendMail({
from: campaign.fromAddress,
to: email,
subject: campaign.subject,
text: plaintext,
html: html
})
.then(result => {
successCount = successCount + 1;
Logger.info("successfully sent email #" + successCount + " - envelope: " + result.envelope.to);
})
.catch(error => {
// set as failed in DB but continue
Logger.error("Error sending campaign email: " + JSON.stringify(error, null, 2))
CampaignEmail.setFailed(campaignEmail.id);
})
})
})
.catch(error => { next(error); });

});

router.post("/fetch-bounces",
@@ -63,7 +247,7 @@ router.post("/fetch-bounces",
(request, response, next) => {

// Notify Admin
Email.sendAdminAlert("Fetch Bounces By " + request.user.email);
Email.sendAdminAlert("ADMIN ACTION", "Fetch Bounces By " + request.user.email);

sqs.receiveMessage({
QueueUrl: `https://sqs.${QUEUE_REGION}.amazonaws.com/${accountId}/${ENVIRONMENT}-BouncesQueue`,
@@ -111,7 +295,7 @@ router.post("/fetch-complaints",
(request, response, next) => {

// Notify Admin
Email.sendAdminAlert("Fetch Complaints By " + request.user.email);
Email.sendAdminAlert("ADMIN ACTION", "Fetch Complaints By " + request.user.email);

sqs.receiveMessage({
QueueUrl: `https://sqs.${QUEUE_REGION}.amazonaws.com/${accountId}/${ENVIRONMENT}-ComplaintsQueue`,
@@ -166,7 +350,7 @@ router.post("/delete-queue-messages",
const receiptHandles = JSON.parse(request.values.receiptHandles);

// Notify Admin
Email.sendAdminAlert("Delete Queue Messages By " + request.user.email);
Email.sendAdminAlert("ADMIN ACTION", "Delete Queue Messages By " + request.user.email);

var entries = [];
ids.forEach( (id, index) => {

0 comments on commit 6067925

Please sign in to comment.