DEV Community

Soma Somorjai
Soma Somorjai

Posted on

React Email in Azure Functions via Resend

The story about using Azure Functions to render and send emails via React Email and Resend.

The need: At Domainly.shop, our Next.js front-end was originally responsible for handling tasks like sending emails (e.g., for user sign-ups). However, to avoid burdening the web app with email rendering and delivery, we decided to offload this functionality to an Azure function.

Step-by-step:

  1. Create a new Azure Function.
  2. Add React, React Email and Resend requirements
  3. Create an email, render it with some props and send it on its way!

Introduction

Sending emails is a critical part of many modern web applications, whether it’s for user sign-ups, password resets, or transactional notifications. However, handling email rendering and delivery directly within your front-end application can lead to performance bottlenecks and unnecessary complexity. Us at Domainly.shop, we faced this challenge with our Next.js front-end, which was initially responsible for sending emails. To improve scalability and offload this workload, we turned to Azure Functions, a serverless compute service, combined with React Email for building dynamic email templates and Resend for reliable email delivery.

This guide walks you through the process of setting up an Azure Function to render and send emails using React Email and Resend. By the end, you’ll have a scalable, maintainable solution for handling email workflows without burdening your front-end application.

Step 1: Setting Up an Azure Function.

Create your Typescript Azure Function from the default template. For this, the easiest if you follow this Microsoft official guide. For simplicity’s sake I will use an HttpTrigger . But you may use any trigger which best fits your needs.

The initial state of our project.
The initial state of our project.

Step 2: Installing Dependencies for React Email and Resend.

Now that we have our Azure Function it is time to add our dependencies for React Email and Resend by running the following commands:
npm install react-email @react-email/components resend
npm install --save-dev @types/react
Add the following scripts to your package.json:

// These scripts will allow you to run and test your emails in dev mode.
"scripts": {
  ...
   // Once we add our first email, npm run email will let us view our emails.
  "email": "email dev -p 4001",
  "export": "email export"
  ...
},
Enter fullscreen mode Exit fullscreen mode

And finally, update your tsconfig.json to handle .jsx and .tsx files.

{
  "compilerOptions": {
    "module": "CommonJS",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "lib": ["dom", "DOM.Iterable", "esnext"],
    "target": "ESNext",
    "outDir": "dist",
    "baseUrl": ".",
    "allowJs": true,
    "sourceMap": true,
    "strict": true,
    "jsx": "react-jsx",
    "skipLibCheck": true
  },
  "exclude": ["node_modules", "dist"],
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "emails/**/*.ts",
    "emails/**/*.tsx"
  ]
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Adding your first Email and delivering it!

3.1 Create your first email

In your project’s root folder create and emails folder. This is where we will place our [email_name].tsx files. For this guide, we will use a very simple email, however, feel free to bling it out after!

// From the Koala tempalte https://demo.react.email/preview/welcome/koala-welcome?view=desktop&lang=jsx
// Import necessary components from React Email
import {
  Body,
  Button,
  Container,
  Head,
  Hr,
  Html,
  Img,
  Preview,
  Section,
  Text,
} from "@react-email/components";

// We define some external prop our email will need to display its content
interface KoalaWelcomeEmailProps {
  userFirstname: string;
}

const baseUrl = "https://yoursite.example";

export const KoalaWelcomeEmail = ({
  userFirstname,
}: KoalaWelcomeEmailProps) => (
  <Html>
    <Head />
    <Preview>
      The sales intelligence platform that helps you uncover qualified leads.
    </Preview>
    <Body style={main}>
      <Container style={container}>
        <Img
          src={`${baseUrl}/static/koala-logo.png`}
          width="170"
          height="50"
          alt="Koala"
          style={logo}
        />
        <Text style={paragraph}>Hi {userFirstname},</Text>
        <Text style={paragraph}>
          Welcome to Koala, the sales intelligence platform that helps you
          uncover qualified leads and close deals faster.
        </Text>
        <Section style={btnContainer}>
          <Button style={button} href="https://getkoala.com">
            Get started
          </Button>
        </Section>
        <Text style={paragraph}>
          Best,
          <br />
          The Koala team
        </Text>
        <Hr style={hr} />
        <Text style={footer}>
          470 Noor Ave STE B #1148, South San Francisco, CA 94080
        </Text>
      </Container>
    </Body>
  </Html>
);

KoalaWelcomeEmail.PreviewProps = {
  userFirstname: "Alan",
} as KoalaWelcomeEmailProps;

export default KoalaWelcomeEmail;

const main = {
  backgroundColor: "#ffffff",
  fontFamily:
    '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif',
};

const container = {
  margin: "0 auto",
  padding: "20px 0 48px",
};

const logo = {
  margin: "0 auto",
};

const paragraph = {
  fontSize: "16px",
  lineHeight: "26px",
};

const btnContainer = {
  textAlign: "center" as const,
};

const button = {
  backgroundColor: "#5F51E8",
  borderRadius: "3px",
  color: "#fff",
  fontSize: "16px",
  textDecoration: "none",
  textAlign: "center" as const,
  display: "block",
  padding: "12px",
};

const hr = {
  borderColor: "#cccccc",
  margin: "20px 0",
};

const footer = {
  color: "#8898aa",
  fontSize: "12px",
};
Enter fullscreen mode Exit fullscreen mode

3.2 Render the email

Normally, we would move our email handling into separate files so they can be nicely separated. However, for this guide’s purposes we will just put it into our function file.

Make sure to update the src/functions/httpTrigger1.ts to src/function/httpTrigger1.tsx since we will be dealing with React components.

First we will create the CreateEmailOptions constant which will contain our email’s information:

import type { CreateEmailOptions } from "resend";

...
export async function httpTrigger1(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
  context.log(`Http function processed request for url "${request.url}"`);  
  const createEmailOptions: CreateEmailOptions = {
      to: ['some-recipient@email.com'],
      from: 'YourFrom <your-from@address.email',
      subject: 'Some Test Subject',
      react: <KoalaWelcomeEmail userFirstname="John" />
  }
}
....
Enter fullscreen mode Exit fullscreen mode

It is the react property which will let us provide a React Component with props so that we can send that as our email.

3.3 Set up Resend

In order to be able to send an email via Resend we will need to set up the RESEND_API_KEY environment variable in our local.settings.json:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "RESEND_API_KEY": "YOUR_KEY_HERE"
  }
}
Enter fullscreen mode Exit fullscreen mode

With this we can expand our code by instanciating the Resend client and sending our email!

...
const resendInstance = new Resend(process.env.RESEND_API_KEY);

try {
    context.log("sending_email_via_resend", {
      to: createEmailOptions.to,
    });
    const response = await resendInstance.emails.send(createEmailOptions);

    if (response.error) {
      context.error("resend_email_error", {
        error: response.error.name,
        message: response.error.message,
      });

      throw new Error(response.error.message);
    }

    if (response.data) {
      context.log("resend_email_data", {
        data: response.data,
      });

      return { body: `Email success with id: ${response.data.id}!` };
    }

    context.warn("resend_no_error_no_data");
    return { body: "No error or data received" };
  } catch (error) {
    if (error instanceof Error) {
      context.error("failed_to_send_email", {
        message: error.message,
        error,
      });
      throw error;
    }

    context.error("failed_to_send_email_unknown_reason", {
      error,
    });

    throw new Error(`Unknown error: Failed to send email, ${error}`);
  }
...
Enter fullscreen mode Exit fullscreen mode

With this code we set up a safe email sending procedure so that we can handle and log all errors if any occurs but more importantly we can send our email!

All is left now is testing the function locally by running it (e.g., using tools like Postman or curl) and deploying it to Azure (e.g., using the Azure CLI or Visual Studio Code).

Conclusion

By leveraging React Email, Resend, and Azure Functions, this guide demonstrates how to efficiently offload email rendering and sending from your front-end application to a serverless architecture. This approach not only improves the scalability and performance of your web app but also simplifies the process of creating dynamic, reusable email templates using React.

The combination of React Email for building templates, Resend for email delivery, and Azure Functions for serverless execution offers several key benefits:

  • Scalability: Offloading email tasks to Azure Functions ensures your front-end remains responsive, even during high traffic.
  • Maintainability: Using React components for email templates allows for better organization, reusability, and consistency in your email designs.
  • Error Handling: The guide provides a robust error-handling mechanism, ensuring that issues are logged and managed effectively.
  • Flexibility: The serverless nature of Azure Functions allows you to trigger email workflows from various sources, such as HTTP requests, timers, or other Azure services.

To take this further, you can expand the solution by adding more email templates, integrating with other triggers (e.g., database changes or event queues), or optimizing the deployment process for production environments. Testing locally and deploying to Azure are critical steps to ensure the solution works seamlessly in real-world scenarios.

By following this guide, you can build a scalable, maintainable, and efficient email-sending workflow that enhances your application’s overall performance and user experience.

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

nextjs tutorial video

Youtube Tutorial Series 📺

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series 👀

Watch the Youtube series