How To Build Your Own Newsletter App? р.2
Tags: webdev, javascript, programming, tutorial
Published: 2024-05-16 11:29:14

## Sending newsletters with Novu and React Email

We’ll leverage Novu’s code-first workflow (Echo) approach in creating notification workflows within our codebase. Novu empowers you with the ability to integrate email, SMS, and chat template and content generators, such as [React Email](https://react.email/), [and MJML](https://mjml.io/) into your app via code.

Within this section, you'll grasp the art of crafting notification workflows using Novu Echo, designing email templates with React Email, and seamlessly sending emails via Novu.

First, you need to [create an account on Novu](https://web.novu.co/auth/signup) and set up a primary email provider. We'll use [Resend](https://resend.com/) for this tutorial.

After creating an account on Novu, create a Resend account, and select `API Keys` from the sidebar menu on your dashboard to create one.


![Resend API key](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vw7rjixor7ofphhtkh5o.png)

Next, return to your Novu dashboard, select `Integrations Store` from the sidebar menu, and add Resend as an email provider. You'll need to paste your Resend API key and email address into the required fields.


![Novu ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y2150tin3je2zid76ggb.png)

Finally, select `Settings` from the sidebar menu and copy your Novu API key into a `.env.local` file as shown below.

```bash
# For Novu SDK
NOVU_API_KEY=<YOUR_NOVU_API_KEY>

# For Echo Client
NEXT_PUBLIC_NOVU_API_KEY=<YOUR_NOVU_API_KEY>
```


![Novu API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nsfoztjd509xbghkwzk2.png)

### The API route for creating newsletters

Navigate to the **`components/Newsletters.tsx`** file, which contains the form that enables Admin users to send newsletters to subscribers. Copy the functions below into this file.

```tsx
const [subscribers, setSubscribers] = useState<SubscribersData[]>([]);

//👇🏻 fetch the subscribers' emails from Firebase
const fetchSubscribers = async () => {
	try {
		const querySnapshot = await getDocs(collection(db, "subscribers"));
		const emails: string[] = [];
		const subs: any = [];
		querySnapshot.forEach((doc) => {
			const dt = doc.data();
			emails.push(dt.email);
			subs.push(dt);
		});
		setSubscribers(subs);
	} catch (e) {
		console.error("Error fetching subscribers", e);
	}
};

//👇🏻 gets the list of subscribers on page load
useEffect(() => {
	fetchSubscribers();
}, []);

//👇🏻 send form data to the backend API route
const emailNewsletter = async () => {
	try {
		const request = await fetch("/api/send", {
			method: "POST",
			body: JSON.stringify({ subject, message, subscribers }),
		});
		const response = await request.json();
		if (response.success) {
			console.log({ response });
		}
	} catch (err) {
		console.error(err);
	}
};
```

The provided code snippet retrieves the list of subscribers from Firebase and sends them, along with the email's message and subject, to the **`/api/send`** API route, where the emails are forwarded to the subscribers via Novu.

The `fetchSubscribers` function retrieves the subscribers from Firebase, while the `emailNewsletter` function sends a POST request containing the subscribers' data, email subject, and content to the `api/send` Next.js API route.

To proceed, let's set up the required API routes. Create an `api/send` folder within the Next.js `app` folder.

```bash
cd app
mkdir api && cd api
mkdir send
```

Create a `route.ts` file within the `send` folder that accepts the form data.

```tsx
import { NextRequest, NextResponse } from "next/server";

export async function POST(req: NextRequest) {
	const { subject, message, subscribers } = await req.json();

	return NextResponse.json(
		{
			message: "Data received!",
			data: {subject, message: subscribers}
			success: true,
		},
		{ status: 200 }
	);
}
```

Now, we can use this data to send email templates using Novu Echo and React Email.

### Code-first email notification workflow with Novu and React Email

Run this code snippet in your terminal to install the [Novu SDK](https://docs.novu.co/sdks/nodejs) and [Novu Echo](https://docs.novu.co/echo/quickstart) to the Next.js project. We'll create the notification workflow with Novu Echo and pass a payload from the API server to the workflow, then into the React Email template.

```bash
npm install @novu/node @novu/echo
```

Next, install React Email by running the following command:

```bash
npm install react-email @react-email/components -E
```

Include the following script in your `package.json` file. The `--dir` flag gives React Email access to the email templates located within the project. In this case, the email templates are located in the `src/emails` folder.

```json
{
	"scripts": {
		"email": "email dev --dir src/emails"
	}
}
```

Run **`npm run email`** in your terminal. This command starts the React Email development server, allowing you to choose from the [existing templates](https://demo.react.email/preview/notifications/vercel-invite-user). Alternatively, you can create an **`emails`** folder containing an **`index.tsx`** file and copy this email template into it.

```tsx
import {
	Body,
	Column,
	Container,
	Head,
	Heading,
	Hr,
	Html,
	Link,
	Preview,
	Section,
	Text,
	Row,
} from "@react-email/components";
import * as React from "react";

const EmailTemplate = () => (
	<Html>
		<Head />
		<Preview>Hello World</Preview>
		<Body style={main}>
			<Container style={container}>
				<Section style={header}>
					<Row>
						<Column style={headerContent}>
							<Heading style={headerContentTitle}>Hello World</Heading>
						</Column>
					</Row>
				</Section>

				<Section style={content}>
					<Text style={paragraph}>Hey Emil,</Text>
					<Text style={paragraph}>Cool</Text>
				</Section>
			</Container>

			<Section style={footer}>
				<Text style={footerText}>
					You&apos;re receiving this email because your subscribed to Newsletter
					App
				</Text>

				<Hr style={footerDivider} />
				<Text style={footerAddress}>
					<strong>Newsletter App</strong>, &copy;{" "}
					<Link href='https://novu.co'>Novu</Link>
				</Text>
			</Section>
		</Body>
	</Html>
);

export default EmailTemplate;

const main = {
	backgroundColor: "#f3f3f5",
	fontFamily: "HelveticaNeue,Helvetica,Arial,sans-serif",
};

const headerContent = { padding: "20px 30px 15px" };

const headerContentTitle = {
	color: "#fff",
	fontSize: "27px",
	fontWeight: "bold",
	lineHeight: "27px",
};

const paragraph = {
	fontSize: "15px",
	lineHeight: "21px",
	color: "#3c3f44",
};

const divider = {
	margin: "30px 0",
};

const container = {
	width: "680px",
	maxWidth: "100%",
	margin: "0 auto",
	backgroundColor: "#ffffff",
};

const footer = {
	width: "680px",
	maxWidth: "100%",
	margin: "32px auto 0 auto",
	padding: "0 30px",
};

const content = {
	padding: "30px 30px 40px 30px",
};

const header = {
	borderRadius: "5px 5px 0 0",
	display: "flex",
	flexDireciont: "column",
	backgroundColor: "#2b2d6e",
};

const footerDivider = {
	...divider,
	borderColor: "#d6d8db",
};

const footerText = {
	fontSize: "12px",
	lineHeight: "15px",
	color: "#9199a1",
	margin: "0",
};

const footerLink = {
	display: "inline-block",
	color: "#9199a1",
	textDecoration: "underline",
	fontSize: "12px",
	marginRight: "10px",
	marginBottom: "0",
	marginTop: "8px",
};

const footerAddress = {
	margin: "4px 0",
	fontSize: "12px",
	lineHeight: "15px",
	color: "#9199a1",
};
```

At this point, you should have an email template ready to integrate into Novu Echo. 🚀

To get started with Novu Echo, close the React Email server, and run the code snippet below. It opens the [Novu Dev Studio](https://docs.novu.co/echo/concepts/studio) in your browser.

```bash
npx novu-labs@latest echo
```

Create an `echo` folder containing a `client.ts` file within the Next.js app folder and copy this code snippet into the file.

```tsx
import { Echo } from "@novu/echo";
import { renderEmail } from "@/emails";

interface EchoProps {
	step: any;
	payload: {
		subject: string;
		message: string;
		firstName: string;
	};
}
export const echo = new Echo({
	apiKey: process.env.NEXT_PUBLIC_NOVU_API_KEY!,
	devModeBypassAuthentication: process.env.NODE_ENV === "development",
});

echo.workflow(
	"newsletter",
	async ({ step, payload }: EchoProps) => {
		await step.email(
			"send-email",
			async () => {
				return {
					subject: `${payload ? payload?.subject : "No Subject"}`,
					body: renderEmail(payload),
				};
			},
			{
				inputSchema: {
					type: "object",
					properties: {},
				},
			}
		);
	},
	{
		payloadSchema: {
			type: "object",
			properties: {
				message: {
					type: "string",
					default: "This is a test message from Newsletter",
				},
				subject: { type: "string", default: "Message from Newsletter App" },
				firstName: { type: "string", default: "User" },
			},
			required: ["message", "subject", "firstName"],
			additionalProperties: false,
		},
	}
);
```

The code snippet defines a Novu notification workflow named `newsletter`, which accepts a `payload` containing the email subject, message, and the recipient's first name. This payload contains the necessary data for the React Email template.

Update the React Email template to receive and display the payload data:

```tsx
const EmailTemplate = ({
	message,
	subject,
	firstName,
}: {
	message: string;
	subject: string;
	firstName: string;
}) => (
	<Html>
		<Head />
		<Preview>{subject}</Preview>
		<Body style={main}>
			<Container style={container}>
				<Section style={header}>
					<Row>
						<Column style={headerContent}>
							<Heading style={headerContentTitle}>{subject}</Heading>
						</Column>
					</Row>
				</Section>

				<Section style={content}>
					<Text style={paragraph}>Hey {firstName},</Text>
					<Text style={paragraph}>{message}</Text>
				</Section>
			</Container>

			<Section style={footer}>
				<Text style={footerText}>
					You&apos;re receiving this email because your subscribed to Newsletter
					App
				</Text>

				<Hr style={footerDivider} />
				<Text style={footerAddress}>
					<strong>Newsletter App</strong>, &copy;{" "}
					<Link href='https://novu.co'>Novu</Link>
				</Text>
			</Section>
		</Body>
	</Html>
);

//👇🏻 passes the payload as props into the component
export function renderEmail(inputs: {
	message: string;
	subject: string;
	firstName: string;
}) {
	return render(<EmailTemplate {...inputs} />);
}
```

The `<EmailTemplate/>` component accepts the email's message, subject, and recipient's first name as props to replace the existing variables within the component.

Next, you need to create an API route for Novu Echo. Within the `api` folder, create an `email` folder containing a `route.ts` file and copy the provided code snippet below into the file.

```tsx
import { serve } from "@novu/echo/next";
import { echo } from "../../echo/client";

export const { GET, POST, PUT } = serve({ client: echo });
```

Make sure you have run npx novu-labs@latest echo in your terminal. This command will automatically open the Novu Dev Studio at this URL: http://localhost:2022/ in your browser. Here, you can select the exact API endpoint you served Novu Echo and preview your email templates before adding to the Novu Cloud Platform.


Once you can preview your email template within the Novu Dev Studio, you can save the workflow to your Novu dashboard. Click the `Sync to Cloud` button at the top right side of the page.


![Novu Dev Studio](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/upxkokevu3cm76maw491.png)

The `Sync to Cloud` button triggers a pop-up that provides instructions on how to push your workflow to the Novu Cloud. 

To proceed, run the following code snippet in your terminal. This will generate a unique URL representing a local tunnel between your development environment and the cloud environment.

```bash
npx localtunnel --port 3000
```


![Novu Dev Studio 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/unho3bp9d8dg1tjmgafa.png)

Copy the generated link along with your Echo API endpoint into the `Echo Endpoint` field and then click the `Create Diff` button.

```
https://<LOCAL_TUNNEL_URL>/<ECHO_API_ENDPOINT>
```

Afterward, scroll down and select `Deploy Changes` to push the workflow to the cloud environment.

![ScreenRecording2024-04-14at07.47.11-ezgif.com-video-to-gif-converter.gif](https://prod-files-secure.s3.us-west-2.amazonaws.com/37c45c24-f7ca-4129-8721-42892a515633/bb9ba57c-75e0-4c35-ae80-a4114f02f48d/ScreenRecording2024-04-14at07.47.11-ezgif.com-video-to-gif-converter.gif)

You can also preview your workflow on the Novu Cloud by clicking the `Test your workflows` link from the notification alert. Congratulations! Your workflow has been successfully deployed.

Now, you can start sending emails via the workflow. Open the `api/send` API route and copy the provided code snippet below into the `route.ts` file.

```tsx
import { NextRequest, NextResponse } from "next/server";
import { SubscribersData } from "../../util";
import { Novu } from "@novu/node";

//👇🏻 Novu SDK for sending emails
const novu = new Novu(process.env.NOVU_API_KEY!);

export async function POST(req: NextRequest) {
	const { subject, message, subscribers } = await req.json();

	subscribers.forEach(async (subscriber: SubscribersData) => {
		const { data } = await novu.trigger("newsletter", {
			to: {
				subscriberId: subscriber.subscriberId,
				email: subscriber.email,
				firstName: subscriber.firstName,
				lastName: subscriber.lastName,
			},
			payload: {
				subject,
				message,
				firstName: subscriber.firstName,
			},
		});
		console.log(data.data);
	});

	return NextResponse.json(
		{
			message: "Emails sent successfully",
			success: true,
		},
		{ status: 200 }
	);
}
```

The code snippet uses the [Novu SDK](https://github.com/novuhq/novu/tree/next/packages/node) to send an email to all the subscribers within the application.

Congratulations! 🎉You've completed the project for this tutorial.

## Conclusion

So far, you've learnt how to implement multiple authentication methods with Firebase, store and retrieve data from Firebase, create email templates with React Email, and send them via Novu.

You also learned how to leverage the [code-first notification workflow approach](https://novu.co/blog/a-code-first-approach-to-managing-notification-workflows/) to build notification workflows within the code while giving your non-technical teammates full control over content and behaviour.

**[Novu](https://github.com/novuhq/novu)** is your best choice to add various notification channels to your applications, including Chat, SMS, Email, Push, and In-app notifications. 

The source code for this tutorial is available here:
[https://github.com/novuhq/newsletter-app-with-novu-echo](https://github.com/novuhq/newsletter-app-with-novu-echo)

Thank you for reading!