---
title: "Send Emails from MCP with React Email & Brevo — Guide"
slug: "send-emails-mcp-react-email-brevo"
published: "2025-12-20"
updated: "2026-01-03"
categories:
  - "React"
tags:
  - "send emails from MCP server"
  - "React Email MCP integration"
  - "Brevo transactional email API"
  - "MCP newsletter automation"
  - "marked markdown to HTML"
  - "AI email automation"
  - "mcp-handler email tool"
  - "render React Email templates"
  - "automated email from Claude"
  - "MCP server email capabilities"
llm-intent: "how-to"
audience-level: "intermediate"
llm-purpose: "Enable MCP servers to send beautifully rendered emails using React Email and Brevo"
llm-prereqs:
  - "Working MCP server from previous guides"
  - "Brevo account with API key"
  - "Verified sender email address"
llm-outputs:
  - "send_newsletter MCP tool working"
  - "React Email template rendering"
  - "Markdown to HTML conversion"
  - "Brevo transactional email delivery"
  - "AI can send emails on command"
---

**Summary Triples**
- (Send Emails from MCP with React Email & Brevo — Guide, expresses-intent, how-to)
- (Send Emails from MCP with React Email & Brevo — Guide, covers-topic, send emails from MCP server)
- (Send Emails from MCP with React Email & Brevo — Guide, provides-guidance-for, Enable MCP servers to send beautifully rendered emails using React Email and Brevo)

### {GOAL}
Enable MCP servers to send beautifully rendered emails using React Email and Brevo

### {PREREQS}
- Working MCP server from previous guides
- Brevo account with API key
- Verified sender email address

### {STEPS}
1. Install dependencies and set env
2. Create reusable React Email component
3. Implement Brevo delivery helper
4. Define MCP tool for sending
5. Render Markdown and send

<!-- llm:goal="Enable MCP servers to send beautifully rendered emails using React Email and Brevo" -->
<!-- llm:prereq="Working MCP server from previous guides" -->
<!-- llm:prereq="Brevo account with API key" -->
<!-- llm:prereq="Verified sender email address" -->
<!-- llm:output="send_newsletter MCP tool working" -->
<!-- llm:output="React Email template rendering" -->
<!-- llm:output="Markdown to HTML conversion" -->
<!-- llm:output="Brevo transactional email delivery" -->
<!-- llm:output="AI can send emails on command" -->

# Send Emails from MCP with React Email & Brevo — Guide
> Send emails from MCP by rendering Markdown with React Email and delivering via Brevo. Step-by-step TypeScript guide to automate personalized newsletters…
Matija Žiberna · 2025-12-20

**This is Part 4 of the MCP Server Series.** This guide assumes you have a working MCP server. If you're starting fresh, begin with [Part 1: Build a Production MCP Server](/blog/build-mcp-server-nextjs).

---

Moving from debugging code in your IDE to logging into an email marketing platform just to send a single, personalized follow-up feels like a massive context switch. I recently faced this when I wanted to notify specific users about fixes relevant to their previous feedback. Accessing that capability directly from my AI chat interface seemed like the perfect solution.

**Email infrastructure patterns**: The React Email templating and Brevo delivery patterns used here are production-ready for any Next.js application. For comprehensive email security implementation, see [building a secure email pipeline](/blog/building-a-secure-email-pipeline-in-next-js). For advanced Brevo template management with dynamic data, check out [mastering Brevo transactional emails](/blog/send-transactional-emails-brevo-templates-dynamic-data).

Here is the step-by-step process I developed to enable my MCP server to send beautifully rendered emails on command.

## Prerequisites

To handle email rendering, markdown processing, and delivery, we need to install a few essential dependencies.

```bash
npm install @react-email/components @react-email/render @getbrevo/brevo marked zod mcp-handler
# or
pnpm add @react-email/components @react-email/render @getbrevo/brevo marked zod mcp-handler
```

You will also need a **Brevo API Key** and a **verified sender email address** from your Brevo account. Add these to your environment variables:

```bash
BREVO_API_KEY=xkeysib-...
BREVO_SENDER_EMAIL=matija@buildwithmatija.com
```

## 1. The Email Infrastructure

To send professional emails, we need a solid foundation. I chose **React Email** for templating because it allows us to build layouts using React components while handling the complex job of inlining CSS for email clients.

First, create a reusable email component with rich styling for content generated via markdown.

```tsx
// File: src/lib/emails/NewsletterEmail.tsx
import { Body, Button, Container, Head, Heading, Html, Preview, Section, Tailwind, Text } from '@react-email/components';
import * as React from 'react';

interface NewsletterEmailProps {
  previewText: string;
  title: string;
  content: string; // HTML content from processed Markdown
  ctaText?: string;
  ctaUrl?: string;
}

export const NewsletterEmail = ({ previewText, title, content, ctaText, ctaUrl }: NewsletterEmailProps) => {
  return (
    <Html>
      <Head>
        <style>{`
          .content-area p { margin: 16px 0; line-height: 1.6; }
          .content-area a { color: #F97316; text-decoration: underline; }
          .content-area blockquote {
            border-left: 4px solid #F97316;
            padding-left: 16px;
            margin: 16px 0;
            color: #4B5563;
            font-style: italic;
          }
        `}</style>
      </Head>
      <Preview>{previewText}</Preview>
      <Tailwind>
        <Body className="bg-[#F9FAFB] m-auto font-sans text-[#111827]">
          <Container className="mb-10 mx-auto p-0 max-w-[600px] bg-white rounded-xl my-[40px] overflow-hidden">
            <Section style={{ backgroundColor: '#D4866D', padding: '40px 24px' }}>
              <Heading className="text-2xl font-bold py-0 px-0 inline-block m-0" style={{ color: 'white' }}>
                Build with Matija
              </Heading>
            </Section>

            <Heading className="text-3xl font-bold text-start p-8 m-0 leading-tight">
              {title}
            </Heading>

            <Section className="px-8 pb-8">
              <div className="content-area" dangerouslySetInnerHTML={{ __html: content }} />
            </Section>

            {ctaText && ctaUrl && (
              <Section className="text-center mt-8 mb-8 px-8">
                <Button
                  className="py-3.5 px-7 rounded-full text-base font-bold"
                  href={ctaUrl}
                  style={{ backgroundColor: '#F97316', color: 'white' }}
                >
                  {ctaText}
                </Button>
              </Section>
            )}
          </Container>
        </Body>
      </Tailwind>
    </Html>
  );
};
```

This component uses a custom `<style>` block in the `<Head>` to ensure that elements inside our `.content-area` (like paragraphs and links) look great when rendered from Markdown.

## 2. The Delivery Backend

Next, we need a helper function to handle the actual transmission via the Brevo SDK. I separated this logic to keep the MCP tool handler focused on execution logic.

```typescript
// File: src/lib/brevo/brevo.ts
import { TransactionalEmailsApi, SendSmtpEmail, TransactionalEmailsApiApiKeys } from '@getbrevo/brevo'

const brevoApiKey = process.env.BREVO_API_KEY
const transactionalEmailsApi = brevoApiKey ? new TransactionalEmailsApi() : null

if (brevoApiKey && transactionalEmailsApi) {
  transactionalEmailsApi.setApiKey(TransactionalEmailsApiApiKeys.apiKey, brevoApiKey)
}

export async function sendTransactionalEmail(params: {
  to: { email: string; name?: string }[]
  subject: string
  htmlContent: string
}) {
  if (!transactionalEmailsApi) {
    return { success: false, error: 'Brevo integration disabled' }
  }

  const senderEmail = process.env.BREVO_SENDER_EMAIL
  if (!senderEmail) {
    return { success: false, error: 'BREVO_SENDER_EMAIL not configured' }
  }

  try {
    const sendSmtpEmail = new SendSmtpEmail()
    sendSmtpEmail.subject = params.subject
    sendSmtpEmail.htmlContent = params.htmlContent
    sendSmtpEmail.sender = { email: senderEmail, name: 'Matija from BuildwithMatija' }
    sendSmtpEmail.to = params.to

    const result = await transactionalEmailsApi.sendTransacEmail(sendSmtpEmail)
    return { success: true, data: result.body }
  } catch (error: any) {
    return { success: false, error: error.message }
  }
}
```

By using `process.env.BREVO_SENDER_EMAIL`, we ensure that the code only attempts to send if we have a verified identity ready.

## 3. The MCP Tool Definition

The final piece is connecting this capability to the MCP server. We define a tool called `send_newsletter` that allows the AI to send messages using Markdown, which we then convert to HTML.

```typescript
// File: src/app/api/mcp/[transport]/route.ts
import * as React from 'react'
import { z } from 'zod'
import { render } from '@react-email/render'
import { marked } from 'marked'
import { createMcpHandler } from 'mcp-handler'
import { NewsletterEmail } from '@/lib/emails/NewsletterEmail'
import { sendTransactionalEmail } from '@/lib/brevo/brevo'

const handler = createMcpHandler((server) => {
    server.tool(
        'send_newsletter',
        'Send a personalized email or newsletter via MCP.',
        {
            subject: z.string().describe('Email subject line'),
            title: z.string().describe('Title shown in the email header'),
            content: z.string().describe('Message content (Markdown supported)'),
            to: z.array(z.string().email()).optional().describe('Direct list of recipients'),
            categoryInterest: z.string().optional().describe('Target category slug'),
            ctaText: z.string().optional(),
            ctaUrl: z.string().url().optional()
        },
        async ({ subject, title, content, to, categoryInterest, ctaText, ctaUrl }) => {
            let recipients = []

            if (to && to.length > 0) {
                recipients = to.map(email => ({ email }))
            } else if (categoryInterest) {
                // Fetch from your database (e.g. Sanity)
                // recipients = await fetchSubscribers(categoryInterest)
            }

            if (recipients.length === 0) {
                return { content: [{ type: 'text', text: 'Error: No recipients found.' }], isError: true }
            }

            // Convert Markdown content provided by AI into HTML
            const processedContent = await marked.parse(content)

            // Render the React Email template to an HTML string
            const htmlContent = await render(
                React.createElement(NewsletterEmail, {
                    previewText: subject,
                    title,
                    content: processedContent,
                    ctaText,
                    ctaUrl
                })
            )

            // Deliver via Brevo
            const result = await sendTransactionalEmail({ to: recipients, subject, htmlContent })

            return {
                content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
            }
        }
    )
})

export { handler as GET, handler as POST }
```

Using `marked.parse(content)` allows the AI to use its natural storytelling abilities—using bold text, lists, and links—while ensuring the recipient sees a perfectly formatted email.

---

## The Complete MCP Server Series

This guide completes the 4-part series on building production-ready MCP servers:

1. **[Why Your Business Needs an MCP Server](/blog/why-your-business-needs-an-mcp-server)** — The business case and ROI
2. **[Part 1: Build a Production MCP Server](/blog/build-mcp-server-nextjs)** — Foundation with Redis-backed SSE
3. **[Part 2: Write Operations](/blog/expanding-mcp-server-nextjs)** — Content editing and cache revalidation
4. **[Part 3: OAuth Security](/blog/oauth-mcp-server-claude)** — Protect your endpoints

By enabling the AI to act on its own suggestions, we move from passive assistance to active automation.

Thanks,
Matija