0

I am working on a nodejs project that involves sending emails to users exactly by 12 am in their own timezone. I tried collecting the user's timezone during registration and storing it in the database. Then I tried looping through the users collection and mailing the user based on his/her timezone but it ended up mailing all users with the same time zone alongside users with no timezone and skipping those with a different timezone entirely. I'm using expressjs, MongoDB for database management, and node-cron to schedule the email sending. I will really appreciate your help guys.

email service file

const nodemailer = require("nodemailer");
const mg = require("nodemailer-mailgun-transport");
const handlebars = require("handlebars");
const fs = require("fs");
const path = require("path");
let cron = require("node-cron");
const { User } = require("../models/user");
const verses = require("kjv/json/verses-1769.json");
const store = require("store2");
const { bible_books } = require("./data");
const _ = require("lodash");

async function getUsersEmail() {
  const users = await User.find().select(["email","timezone"]);
  return users;
}
  
module.exports = async function () {
  const emailTemplateSource = fs.readFileSync(
    path.join(__dirname, "../views/template.hbs"),
    "utf8"
  );

  const mailgunAuth = {
    auth: {
      api_key: process.env.mailgun_apikey,
      domain: process.env.mailgun_domain,
    },
  };

  const smtpTransport = nodemailer.createTransport(mg(mailgunAuth));

  const template = handlebars.compile(emailTemplateSource);

  (await getUsersEmail()).map(async function (value) {
    cron.schedule("0 0 * * *", async function () {
      console.log("running task every day at 12:00 am");
      const bible_book = _.sampleSize(bible_books, 1);
      store("bible", bible_book[0]);
      let verse = store("bible");
      let bible_passage = verse;
      let bible_text = verses[bible_passage];
      await User.findByIdAndUpdate(
        value?._id,
        {
          bible: {
            verse: bible_passage,
            text: bible_text,
          },
        },
        { new: true }
      );

      const htmlToSend = template({
        verse: bible_passage,
        text: bible_text,
         imageUrl:"https://world.png",
        redirectUrl: "https://redirecturl.com/home",
        year: new Date().getFullYear(),
      });

         const mailOptions = {
            from: "from@domain.org",
            to: value?.email,
            subject: "Send",
            html: htmlToSend,
          };
          smtpTransport.sendMail(mailOptions, function (error, response) {
            if (error) {
              console.log(error);
            } else {
              console.log(`Successfully sent email to ${mailOptions.to}.`);
            }
          });
    
        }, {
          scheduled: true,
          timezone:value?.timezone
        });
        console.log(value?.timezone)
      });
    };

calling my service file in my index.js

require("./service/emailServiceFile")();

1 Answers1

0

There are many approaches to do this but let's discuss your solution

  1. The time is midnight[12:00] somewhere around the globe now, so the schedule should run every hour not day.

    cron.schedule("0 * * * *", ...

  2. You need to check if it is after 12:00 am in the user's timezone with something like this.

     if (new Date(new Date().toLocaleString('en-us', { timeZone: value?.timezone })).getHours() == 0) { //Send Emails }
    
Ashraf Basry
  • 58
  • 1
  • 5
  • I don't want to send the mail after 12 am bro I want to send the mail exactly by 12 am on each user timezone, also the value?.timezone property is gotten from the user's database info. If you feel my approach is the problem pls suggest another approach – Godwin Ehikhamhen May 29 '22 at 08:48
  • @GodwinEhikhamhen I meant by after is a fraction of a minute or seconds depending on the users' list size and the time it gonna take to process it. – Ashraf Basry May 30 '22 at 11:38
  • you know what bro pls suggest another approach for me – Godwin Ehikhamhen Jun 02 '22 at 15:17