/how-to-build-replit

How to Build a Email automation with Replit

Learn how to build an email automation using Replit. Follow our step-by-step guide to streamline your email tasks efficiently and easily.

Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

How to Build a Email automation with Replit

To build an email automation in Replit, you can use Node.js with a simple scheduler (using node-cron) and an email library like nodemailer. You’ll put the main logic inside an index.js file, store credentials safely in Replit Secrets, and test emails right from your Repl. Replit can stay awake if you upgrade to “Always On,” or you can manually run it when needed. This setup will let you send automated emails at chosen times or in response to an event in your app.

 

Project Setup in Replit

 

Create a new Node.js Repl (when asked “Language,” select Node.js). The main file (created automatically) is index.js. You’ll write your main logic there.

  • In the Replit sidebar, you’ll see a “Secrets” tab (key icon). Add environment variables there — they stay hidden and safe. You’ll need these for your email credentials.
  • Name your secrets like EMAIL_USER and EMAIL_PASS if using Gmail or similar service.
  • Open the Shell tab at the bottom and install two packages by running:
npm install nodemailer node-cron

 

Basic Email Sending Code

 

Below is a working example of how to send an email. This goes inside your existing index.js file in the root directory.

const nodemailer = require("nodemailer");
const cron = require("node-cron");

// Create reusable transporter using SMTP
const transporter = nodemailer.createTransport({
  service: "gmail", // You can also use another SMTP provider
  auth: {
    user: process.env.EMAIL_USER, // Loaded from your Replit Secrets
    pass: process.env.EMAIL_PASS
  }
});

// Function that sends an email
function sendMail() {
  const mailOptions = {
    from: process.env.EMAIL_USER,
    to: "[email protected]", // Replace with a real address
    subject: "Automated Email from Replit",
    text: "This is an automated email sent from your Replit project!"
  };

  transporter.sendMail(mailOptions, (error, info) => {
    if (error) {
      console.log("Error sending mail:", error);
    } else {
      console.log("Email sent successfully:", info.response);
    }
  });
}

// Run immediately to test
sendMail();

Run the Repl by clicking the “Run” button. Check the console for “Email sent successfully.” This proves that your SMTP credentials and Replit network connection work.

 

Add Email Automation (Scheduled Task)

 

If you want to send emails automatically at certain times, add this code at the bottom of the same index.js file:

// Run every day at 9 AM UTC
cron.schedule("0 9 * * *", () => {
  console.log("Running daily email automation...");
  sendMail();
});

The “0 9 _ _ _” pattern is a cron expression — it means “run at 09:00 UTC every day.” You can customize that pattern as needed (for example, “_/5 _ _ _ _” runs every 5 minutes).

Important note: On a free Replit plan, your Repl sleeps after inactivity, so cron won’t run while it’s asleep. If you upgrade to a Hacker plan and turn on “Always On” in your project's settings, the schedule will keep working in the background.

 

Optional: Better Project Structure

 

When your project grows, you might want to clean things up to stay organized:

  • Create a utils folder, and inside it add a file called mailer.js. Move the transporter and sendMail function there.
  • In index.js, just import and call these functions. This keeps your main file cleaner.
// Inside utils/mailer.js
const nodemailer = require("nodemailer");

let transporter = nodemailer.createTransport({
  service: "gmail",
  auth: {
    user: process.env.EMAIL_USER,
    pass: process.env.EMAIL_PASS
  }
});

function sendMail(to, subject, text) {
  const mailOptions = { from: process.env.EMAIL_USER, to, subject, text };
  return transporter.sendMail(mailOptions);
}

module.exports = sendMail;

// Inside index.js
const cron = require("node-cron");
const sendMail = require("./utils/mailer");

cron.schedule("0 9 * * *", async () => {
  await sendMail("[email protected]", "Daily report", "Your daily report is ready!");
  console.log("Sent daily report email");
});

 

Troubleshooting & Tips

 

  • If Gmail blocks your connection, use an App Password (recommended) instead of your main password. You set this up in your Google account’s security settings.
  • If you use another email provider, replace service: "gmail" with custom SMTP settings — for example, host, port, and secure.
  • Don’t hardcode passwords or keys in your code. Always keep them in Replit Secrets.
  • Test manually before adding a schedule to ensure everything sends properly.

 

This setup gives you a functional email automation running completely inside Replit — using real code, handling credentials securely, and adaptable for production use if you connect it to a database or API later.

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Contact Us

How to Send Automated Emails with Node.js and Replit


import express from "express";
import bodyParser from "body-parser";
import nodemailer from "nodemailer";

const app = express();
app.use(bodyParser.json());

// Simple in-memory queue to prevent sending duplicate emails too quickly
const emailQueue = new Map(); // key: recipientEmail, value: timestamp of last send

const transporter = nodemailer.createTransport({
  service: "gmail",
  auth: {
    user: process.env.SENDER\_EMAIL,
    pass: process.env.SENDER\_PASS
  }
});

app.post("/send-email", async (req, res) => {
  const { to, subject, message } = req.body;
  if (!to || !subject || !message) return res.status(400).json({ error: "Missing fields" });

  const lastSent = emailQueue.get(to);
  if (lastSent && Date.now() - lastSent < 1000 \* 60) {
    return res.status(429).json({ error: "Too many requests. Try again later." });
  }

  try {
    await transporter.sendMail({
      from: process.env.SENDER\_EMAIL,
      to,
      subject,
      html: `

${message}

` }); emailQueue.set(to, Date.now()); res.json({ success: true }); } catch (err) { res.status(500).json({ error: err.message }); } }); app.listen(3000, () => console.log("Email service running on port 3000"));

How to Automate Welcome Emails with Webhooks and SendGrid on Replit


import express from "express";
import axios from "axios";
import crypto from "crypto";

const app = express();
app.use(express.json());

// This endpoint triggers an automated email through a 3rd-party API (e.g., SendGrid)
// when a new customer is added via a webhook. Includes HMAC verification for security.

app.post("/webhooks/new-customer", async (req, res) => {
  const signature = req.headers["x-signature"];
  const secret = process.env.WEBHOOK\_SECRET;
  const computed = crypto
    .createHmac("sha256", secret)
    .update(JSON.stringify(req.body))
    .digest("hex");

  if (computed !== signature) {
    return res.status(401).json({ error: "Invalid signature" });
  }

  const { email, name } = req.body;
  if (!email || !name) return res.status(400).json({ error: "Missing email or name" });

  try {
    await axios.post("https://api.sendgrid.com/v3/mail/send", {
      personalizations: [{ to: [{ email }], subject: "Welcome!" }],
      from: { email: process.env.SENDER\_EMAIL },
      content: [
        {
          type: "text/html",
          value: \`
            

Hello ${name}, welcome aboard!

We're excited to have you. Here's a quick start guide.

\` } ] }, { headers: { Authorization: `Bearer ${process.env.SENDGRID_API_KEY}`, "Content-Type": "application/json" } }); res.json({ success: true }); } catch (err) { console.error("Failed to send email:", err.message); res.status(500).json({ error: "Failed to send email" }); } }); app.listen(3000, () => console.log("Webhook listener running on port 3000"));

How to Build an Email Automation Service with Retry Queue on Replit


import express from "express";
import nodemailer from "nodemailer";
import Database from "@replit/database";

const db = new Database();
const app = express();
app.use(express.json());

// Automated email retry queue using Replit DB to persist state across runs
const transporter = nodemailer.createTransport({
  service: "gmail",
  auth: {
    user: process.env.SENDER\_EMAIL,
    pass: process.env.SENDER\_PASS,
  },
});

async function enqueueEmail(job) {
  const queue = (await db.get("email\_queue")) || [];
  queue.push({ ...job, attempts: 0 });
  await db.set("email\_queue", queue);
}

// Simple interval-based job runner (simulate cron)
setInterval(async () => {
  const queue = (await db.get("email\_queue")) || [];
  if (queue.length === 0) return;

  const remaining = [];
  for (const job of queue) {
    try {
      await transporter.sendMail({
        from: process.env.SENDER\_EMAIL,
        to: job.to,
        subject: job.subject,
        html: job.html,
      });
      console.log(`Email sent to ${job.to}`);
    } catch (err) {
      job.attempts += 1;
      if (job.attempts < 3) remaining.push(job);
      else console.error(`Failed after 3 attempts: ${job.to}`, err.message);
    }
  }
  await db.set("email\_queue", remaining);
}, 1000 \* 60); // every minute

app.post("/schedule-email", async (req, res) => {
  const { to, subject, html } = req.body;
  if (!to || !subject || !html) return res.status(400).json({ error: "Missing fields" });

  await enqueueEmail({ to, subject, html });
  res.json({ success: true, message: "Email scheduled" });
});

app.listen(3000, () => console.log("Email automation service running on port 3000"));

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Contact Us
Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

Best Practices for Building a Email automation with Replit

If you want to build a reliable email automation system on Replit, use a Node.js backend (Express is a good choice), handle your API keys safely using Replit Secrets, use a trusted mail service like Nodemailer (for SMTP) or a transactional email API (like SendGrid), and separate your logic into small clear files: one for server logic (index.js), one for email logic (mailer.js), and a simple HTML form (for testing) in index.html. Keep secrets out of your code — only use Replit Secrets tab. Replit runs 24/7 only if you use Deployments or Always On, so plan accordingly if you need scheduled or automated sending.

 

Step 1: Setup your Replit environment

 

  • Create a new Repl using the “Node.js” template.
  • In the Replit left panel, open the Secrets (lock icon) and set environment variables:
    • EMAIL\_USER (your email address)
    • EMAIL\_PASS (app password / SMTP token)
  • In the Replit Shell, install required packages:
npm install express nodemailer

 

Step 2: Create your server file (index.js)

 

This file runs your Express server and handles requests that trigger emails. Place this file at your Replit project root (Replit does it automatically when created).

// index.js
import express from "express";
import { sendEmail } from "./mailer.js"; // Import the mailer function

const app = express();
app.use(express.json()); // enables reading JSON from requests

// create an endpoint for triggering email automation
app.post("/send", async (req, res) => {
  const { to, subject, body } = req.body;

  try {
    await sendEmail(to, subject, body); // call the mailer
    res.json({ success: true, message: "Email sent successfully!" });
  } catch (error) {
    console.error(error);
    res.status(500).json({ success: false, error: "Failed to send email." });
  }
});

app.listen(3000, () => {
  console.log("Server running on port 3000");
});

 

Step 3: Create the mail sending logic (mailer.js)

 

This file contains the actual sending function, separated so you can reuse or test it independently. Always read credentials from process.env since Replit injects your secrets automatically.

// mailer.js
import nodemailer from "nodemailer";

// create and export reusable function
export async function sendEmail(to, subject, body) {
  // Configure SMTP transport
  const transporter = nodemailer.createTransport({
    service: "gmail", // works for Gmail or you can change to custom SMTP
    auth: {
      user: process.env.EMAIL_USER,
      pass: process.env.EMAIL_PASS,
    },
  });

  const mailOptions = {
    from: process.env.EMAIL_USER,
    to,
    subject,
    html: `<p>${body}</p>`, // HTML content of email
  };

  // send email
  await transporter.sendMail(mailOptions);
}

 

Step 4: (optional) Create a frontend to test it (index.html)

 

To make it easy for non‑developers to trigger emails, you can have a small test form. In Replit, create index.html in the root folder and link it via Express’s static middleware or open it manually.

<!-- index.html -->
<!DOCTYPE html>
<html>
  <body style="font-family:sans-serif;">
    <h3>Send Test Email</h3>
    <form id="emailForm">
      <input type="email" id="to" placeholder="Recipient" required/><br/><br/>
      <input type="text" id="subject" placeholder="Subject" required/><br/><br/>
      <textarea id="body" placeholder="Email body"></textarea><br/><br/>
      <button type="submit">Send Email</button>
    </form>

    <script>
      const form = document.getElementById("emailForm");
      form.addEventListener("submit", async (e) => {
        e.preventDefault();
        const data = {
          to: document.getElementById("to").value,
          subject: document.getElementById("subject").value,
          body: document.getElementById("body").value
        };
        const res = await fetch("/send", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(data)
        });
        const result = await res.json();
        alert(result.message || result.error);
      });
    </script>
  </body>
</html>

 

Step 5: Replit Deployment and Automation Tips

 

  • Don’t store credentials in code. Always use the Secrets tab. Never git-commit your password or app tokens.
  • Test using the Replit "Run" button. Your app will expose a public URL (something like https://yourrepl.username.repl.co).
  • For automation (scheduled emails): Replit doesn’t allow traditional cron jobs on free containers. Instead, use an external service like cron-job.org to ping your Replit endpoint periodically.
  • For reliability: Use the “Deployments” tab ➜ “Always On” or “Autoscale” if you’re sending on schedule or from webhook calls; otherwise the Repl will sleep after inactivity.
  • Logging: Check the “Console” tab — Replit shows server logs live. Use console.log() generously when debugging.

 

Advanced Notes

 

  • Use rate limiting (like express-rate-limit) if you publicly expose the send endpoint, to prevent abuse.
  • For production email sending (>100/day), consider SendGrid or Resend instead of Gmail SMTP; you can still integrate them easily via their npm packages and store tokens in Secrets.
  • Use a database (like Replit DB or external DB) if you want to queue or log sent emails.

 

This approach respects Replit’s constraints, keeps your credentials safe, and gives you a working, realistic base for email automation — not just a demo, but something you can extend for real projects.

Client trust and success are our top priorities

When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.

Rapid Dev was an exceptional project management organization and the best development collaborators I've had the pleasure of working with. They do complex work on extremely fast timelines and effectively manage the testing and pre-launch process to deliver the best possible product. I'm extremely impressed with their execution ability.

CPO, Praction - Arkady Sokolov

May 2, 2023

Working with Matt was comparable to having another co-founder on the team, but without the commitment or cost. He has a strategic mindset and willing to change the scope of the project in real time based on the needs of the client. A true strategic thought partner!

Co-Founder, Arc - Donald Muir

Dec 27, 2022

Rapid Dev are 10/10, excellent communicators - the best I've ever encountered in the tech dev space. They always go the extra mile, they genuinely care, they respond quickly, they're flexible, adaptable and their enthusiasm is amazing.

Co-CEO, Grantify - Mat Westergreen-Thorne

Oct 15, 2022

Rapid Dev is an excellent developer for no-code and low-code solutions.
We’ve had great success since launching the platform in November 2023. In a few months, we’ve gained over 1,000 new active users. We’ve also secured several dozen bookings on the platform and seen about 70% new user month-over-month growth since the launch.

Co-Founder, Church Real Estate Marketplace - Emmanuel Brown

May 1, 2024 

Matt’s dedication to executing our vision and his commitment to the project deadline were impressive. 
This was such a specific project, and Matt really delivered. We worked with a really fast turnaround, and he always delivered. The site was a perfect prop for us!

Production Manager, Media Production Company - Samantha Fekete

Sep 23, 2022