Build Automated Email Sequences - Shootmail + Upstash Workflow (For Devs)

Published :
subhendu singh subhendu singh
Build Automated Email Sequences - Shootmail + Upstash Workflow (For Devs)

Personalized email marketing is no longer a luxury, it’s a necessity. But for developers and SaaS owners, setting up reliable and engaging email sequences can feel like a constant battle. You’re juggling design, content, and the complexities of ensuring your emails actually get delivered. What if you could automate this entire process, creating powerful drip campaigns without sacrificing scalability or reliability?

That’s where Shootmail and Upstash Workflow come in. This guide will show you how to build robust email sequences and drip campaigns using Shootmail’s intuitive email builder and Upstash Workflow’s durable serverless functions. No more worrying about serverless function timeouts or lost leads – just scalable, personalized email marketing that works.

#Understanding Email Sequences and Drip Campaigns

#Before diving into the code, let’s clarify the basics:

  • What is an Email Sequence? An email sequence is a pre-written series of automated emails triggered by a specific user action, like signing up for a trial, downloading a resource, or making a purchase. These sequences are designed to guide users through a specific journey.
  • What is a Drip Campaign? Think of a drip campaign as an email sequence’s more sophisticated cousin. Email drip campaigns are also automated, but often used for longer-term engagement, building relationships, educating users about your product, and driving conversions over time.

#Why are these strategies so important for SaaS businesses?

  • Increased user engagement and retention: Keep your users active and informed with personalized content.
  • Automated lead nurturing and sales: Guide potential customers through the sales funnel with targeted messaging.
  • Scalable personalized communication: Send the right message to the right user at the right time, without manual effort.

#The Power of Shootmail for Email Creation

Stop wrestling with HTML and start crafting beautiful, high-converting emails with Shootmail.

  • Shootmail: Email Templates and Design Without the Headache: Shootmail’s intuitive notion like email builder lets you design stunning emails in minutes, even without design expertise. Choose from a wide variety of pre-built, high-converting email templates to jumpstart your campaigns. Check out our blog post on 10 High-Converting Email Templates Every Solo Entrepreneur Needs for inspiration or checkout our entire templates catalogue. Plus, Shootmail ensures your emails look great on any device with mobile-responsive design and dark mode support. You can also check our email inspiration directory containing email campaigns from well known brands like Adobe, Apple, Blinkist, Canva etc.
  • Shootmail SDK: Integrate and Send Emails Directly From Code: For developers who prefer a code-first approach, the Shootmail SDK provides a powerful way to send emails directly from your applications. The SDK offers a unified interface for integrating with multiple email providers, including Resend, Mailchimp, SendGrid, Postmark, AWS SES and Emailit. Say goodbye to managing individual API keys and libraries for each provider!

Here’s a basic example of initializing the Shootmail client and sending an email:

Install Shootmail’s SDK:

npm i shootmail

Initialize and Shoot:

import { Shootmail } from "shootmail";

//initialize Shootmail
const shootmail = new Shootmail({
  shootmailApiKey: "YOUR_SHOOTMAIL_API_KEY",
  providers: [
    {
      provider: "resend",
      apiKey: "YOUR_RESEND_API_KEY",
    },
  ],
});

//Shoot your mail
const response = await shootmail.shoot({
  templateId: "YOUR_TEMPLATE_ID",
  from: { email: "updates@mail.shootmail.app", name: "Shootmail" },
  to: [{ email: "user@example.com" }],
  subject: "Welcome to Our SaaS!",
  data: { userName: "John Doe" },
});

console.log(response);

See the complete Shootmail SDK documentation for more details.

  • Exporting Shootmail Templates: You can also export the emails directly from Shootmail to MailChimp, Brevo, SendGrid. This ensures that the designed email sequence can be exported to other services for marketing automation.

#Upstash Workflow: Reliable Automation for Email Sequences

Now that you’ve created your beautiful email templates with Shootmail, it’s time to automate the sending process with Upstash Workflow.

  • What is Upstash Workflow? Upstash Workflow lets you write durable, reliable and performant serverless functions. Think of it as a way to orchestrate complex tasks without worrying about infrastructure management.
  • Why Use Upstash Workflow for Email Sequences?
    • Guarantee email delivery: Upstash Workflow ensures that your emails are sent, even in the face of temporary outages or serverless function timeouts with retries.
    • Handle long delays: Implement delays between emails in your sequence without function timeouts. Upstash Workflow can “sleep” for days, weeks, or even months.
    • Implement complex logic: Create branching email sequences based on user behavior or other conditions.

#Building an Email Sequence with Shootmail and Upstash Workflow: A Code Example

Let’s build a welcome email sequence for new SaaS sign-ups. This sequence will consist of three emails:

  1. A welcome email sent immediately after sign-up.
  2. A follow-up email sent after three days.
  3. A final email sent after a week, encouraging users to upgrade.

#Step 1: Setting up the Workflow Endpoint (Upstash Workflow)

First, we need to define a workflow endpoint using Upstash Workflow’s serve method. This endpoint will receive the initial user data and trigger the email sequence.

Install Upstash workflow SDK

npm install @upstash/workflow

Import and use:

import { serve } from "@upstash/workflow/nextjs";

export const { POST } = serve(async (context) => {
  const { userId, email } = context.requestPayload;

  // Your email sequence logic will go here
});

See the Upstash Workflow Create a workflow documentation for more.

#Step 2: Sending the First Welcome Email (Shootmail SDK)

Now, let’s use the Shootmail SDK to send the initial welcome email. We’ll use the shoot method and provide the template ID, recipient email, and any personalized data.

import { serve } from "@upstash/workflow/nextjs";
import { Shootmail } from "shootmail";

export const { POST } = serve(async (context) => {
  const { userId, email } = context.requestPayload;

  // Send the welcome email using Shootmail
  const shootmail = new Shootmail({
    shootmailApiKey: "YOUR_SHOOTMAIL_API_KEY",
    providers: [
      {
        provider: "resend",
        apiKey: "YOUR_RESEND_API_KEY",
      },
    ],
  });
  const response = await shootmail.shoot({
    templateId: "YOUR_WELCOME_TEMPLATE_ID",
    from: { email: "updates@mail.shootmail.app", name: "Shootmail" },
    to: [{ email: email }],
    subject: "Welcome to Our SaaS!",
    data: { userId: userId }, // any data for personalization
  });

  console.log(response); // Log the response from Shootmail
});

Remember to replace “YOUR_WELCOME_TEMPLATE_ID” with the actual ID of your welcome email template in Shootmail.

#Step 3: Delaying the Next Email (Upstash Workflow)

To delay the sending of the next email in the sequence, we’ll use Upstash Workflow’s context.sleep method. This will pause the workflow for three days.

import { serve } from "@upstash/workflow/nextjs";
import { Shootmail } from "shootmail";

export const { POST } = serve(async (context) => {
  const { userId, email } = context.requestPayload;

  // Send the welcome email using Shootmail (as shown above)

  // Delay the next email for three days
  await context.sleep("delay-follow-up", 3 * 24 * 60 * 60);

  // Send the follow-up email (code will be added in the next step)
});

#Step 4: Checking User Activity (Upstash Workflow)

Before sending the follow-up email, let’s check if the user has been active on our SaaS platform. We’ll need to integrate with your application’s data store to retrieve this information.

import { serve } from "@upstash/workflow/nextjs";
import { Shootmail } from "shootmail";

export const { POST } = serve(async (context) => {
  const { userId, email } = context.requestPayload;

  // Send the welcome email using Shootmail (as shown above)

  // Delay the next email for three days
  await context.sleep("delay-follow-up", 3 * 24 * 60 * 60);

  // Check if the user has been active
  const isActive = await context.run("check-user-activity", async () => {
    // Replace this with your actual data store integration
    const userActivity = await getUserActivity(userId);
    return userActivity.lastLogin > Date.now() - 3 * 24 * 60 * 60 * 1000; // Check if logged in within the last 3 days
  });

  // Send the follow-up email based on user activity (code will be added in the next step)
});

async function getUserActivity(userId: string) {
  // Implement your data store logic here
  return { lastLogin: Date.now() - 2 * 24 * 60 * 60 * 1000 };
}

#Step 5: Sending a Follow-Up Email (Shootmail SDK)

Finally, let’s send a personalized follow-up email based on user activity.

import { serve } from "@upstash/workflow/nextjs";
import { Shootmail } from "shootmail";

export const { POST } = serve(async (context) => {
  const { userId, email } = context.requestPayload;

  // Send the welcome email using Shootmail (as shown above)

  // Delay the next email for three days
  await context.sleep("delay-follow-up", 3 * 24 * 60 * 60);

  // Check if the user has been active
  const isActive = await context.run("check-user-activity", async () => {
    // Replace this with your actual data store integration
    const userActivity = await getUserActivity(userId);
    return userActivity.lastLogin > Date.now() - 3 * 24 * 60 * 60 * 1000; // Check if logged in within the last 3 days
  });

  // Send the follow-up email based on user activity
  if (isActive) {
    const response = await shootmail.shoot({
      templateId: "YOUR_ACTIVE_TEMPLATE_ID",
      from: { email: "updates@mail.shootmail.app", name: "Shootmail" },
      to: [{ email: email }],
      subject: "Welcome Back!",
      data: { userId: userId },
    });
    console.log(response);
  } else {
    const response = await shootmail.shoot({
      templateId: "YOUR_INACTIVE_TEMPLATE_ID",
      from: { email: "updates@mail.shootmail.app", name: "Shootmail" },
      to: [{ email: email }],
      subject: "We Miss You!",
      data: { userId: userId },
    });
    console.log(response);
  }
});

async function getUserActivity(userId: string) {
  // Implement your data store logic here
  return { lastLogin: Date.now() - 2 * 24 * 60 * 60 * 1000 };
}

Remember to replace “YOUR_ACTIVE_TEMPLATE_ID” and “YOUR_INACTIVE_TEMPLATE_ID” with the actual IDs of your follow-up email templates in Shootmail.

#Complete Example

Here is the complete email sequence example that is used in Shootmail to welcome and follow up the users

#Coding email sequence

import { serve } from "@upstash/workflow/nextjs";
import { Resend } from "@upstash/workflow/integrations/resend";

export const { POST } = serve(async (context) => {
  // Send email
  const payload = context.requestPayload;
  
  if (!payload) {
    throw new Error("Payload not found");
	}
	
	const result1 = await shootmail.shoot({
    templateId: "YOUR_WELCOME_TEMPLATE_ID",
    from: { email: "updates@mail.shootmail.app", name: "Shootmail" },
    to: [{ email: email }],
    subject: "Welcome to Our SaaS!",
    data: { userId: userId },
  });
	
	console.log("Step 1 has been executed, result", result1);
	
	await context.sleep("Step 2: Wait for 2 days", 2 * 24 * 60 * 60);
	
	const result2 = await context.run("Step 3: Check if user has purchased a plan", async () => {
	    const isPaidUser = await hasUserPurchasedPlan();
	
	    if (isPaidUser.isErr()) {
	        return {
	            isPaidUser: false,
	            result: isPaidUser.error
	        };
	    }
	
	    console.log("isPaidUser", isPaidUser.value);
	
	    if (!isPaidUser.value) {
	        // user has not purchased a plan after 2 days of signup
	        const response = await shootmail.shoot({
				    templateId: "YOUR_FOLLOW_UP_TEMPLATE_ID",
				    from: { email: "updates@mail.shootmail.app", name: "Shootmail" },
				    to: [{ email: email }],
				    subject: "Special offer for you",
				    data: { userId: userId },
				  });
	
	        return {
	            isPaidUser: false,
	            result: response
	        };
	    } else {
	        // user has purchased a plan after 2 days of signup, ask for feedback
	        console.log("user has purchased a plan after 2 days of signup, ask for feedback");
	        const response = await shootmail.shoot({
				    templateId: "YOUR_FEEDBACK_TEMPLATE_ID",
				    from: { email: "updates@mail.shootmail.app", name: "Shootmail" },
				    to: [{ email: email }],
				    subject: "Wanted to say Hi and get your feedback",
				    data: { userId: userId },
				  });
	
	        return {
	            isPaidUser: true,
	            result: response
	        };
	    }
	});
	
	console.log("Step 3 has been executed, result", result2);
});

#Triggering workflow

import { Client } from "@upstash/workflow";

const client = new Client({ token: c.env.QSTASH_TOKEN });
    
const { messageId } = await client.trigger({
     url: "your-workflow-endpoint",
     body: data,
     retries: 3
});

Remember, for local development, use a tool like ngrok or cloudflare tunnels to generate a https url to test your workflow.

#Advanced Email Sequence Strategies with Shootmail and Upstash Workflow

This is just the beginning! With Shootmail and Upstash Workflow, you can implement even more sophisticated email marketing strategies:

#Personalization

  • Tailor email content based on detailed user data, behavior patterns, and individual preferences.
  • Leverage Shootmail’s templating capabilities and Upstash Workflow’s seamless data access.

#A/B Testing

  • Experiment with different email subject lines, content variations, and sending times to optimize campaign performance.
  • Use Upstash Workflow to randomly assign users to different test groups and track results.

#Segmentation

  • Divide your email list into segments based on demographics, interests, or specific actions taken within your SaaS platform.
  • Develop tailored email sequences for each segment to maximize relevance and engagement.

#Integration with Other Tools

  • Webhooks: Trigger email sequences based on events from other applications, such as new sign-ups, completed purchases, or canceled subscriptions. Learn how to trigger workflows from webhooks in the Upstash documentation.
  • AI Builder: Use the Shootmail AI email builder trained to create professional emails inside the Shootmail email editor so that you can customize the emails quickly.

#Shootmail and Upstash Workflow: The Perfect Combination for Developers

Building automated email sequences and drip campaigns doesn’t have to be a headache. Shootmail and Upstash Workflow empower developers to create powerful, personalized email marketing experiences with ease. With Shootmail’s intuitive email builder and SDK alongside Upstash Workflow’s reliable automation, you can focus on growing your SaaS business, not managing infrastructure.

Ready to level up your email marketing? Sign up for Shootmail and Upstash today and start building your own automated email sequences!