• Home
BuildWithMatija
Get In Touch
Part 4·Building MCP Servers with Next.js
  1. Home
  2. Blog
  3. React
  4. Send Emails from MCP with React Email & Brevo — Guide

Send Emails from MCP with React Email & Brevo — Guide

Enable your MCP server to render Markdown with React Email and deliver transactional emails via Brevo; includes…

20th December 2025·Updated on:3rd January 2026·MŽMatija Žiberna·
React
Send Emails from MCP with React Email & Brevo — Guide

⚛️ Advanced React Development Guides

Comprehensive React guides covering hooks, performance optimization, and React 19 features. Includes code examples and prompts to boost your workflow.

No spam. Unsubscribe anytime.

Related Posts:

  • •Build an MCP Server in Next.js for Claude Code (Complete Guide)
  • •Build a Working MCP Server: Custom JSON-RPC Implementation
  • •Build a Production MCP Server in Next.js — Quick Guide
  • •Build a Claude SEO Agent with Google Search Console MCP Integration
  • •Building Secure Multi-User MCP Servers: Claude vs OpenAI's Authentication Gap
  • •Persist Google OAuth Refresh Tokens with Next.js & Redis

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.


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. For advanced Brevo template management with dynamic data, check out mastering Brevo transactional emails.

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.

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:

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.

// 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.

// 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.

// 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 — The business case and ROI
  2. Part 1: Build a Production MCP Server — Foundation with Redis-backed SSE
  3. Part 2: Write Operations — Content editing and cache revalidation
  4. Part 3: OAuth Security — Protect your endpoints

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

Thanks, Matija

📄View markdown version
5

Frequently Asked Questions

Comments

Leave a Comment

Your email will not be published

Stay updated! Get our weekly digest with the latest learnings on NextJS, React, AI, and web development tips delivered straight to your inbox.

10-2000 characters

• Comments are automatically approved and will appear immediately

• Your name and email will be saved for future comments

• Be respectful and constructive in your feedback

• No spam, self-promotion, or off-topic content

Matija Žiberna
Matija Žiberna
Full-stack developer, co-founder

I'm Matija Žiberna, a self-taught full-stack developer and co-founder passionate about building products, writing clean code, and figuring out how to turn ideas into businesses. I write about web development with Next.js, lessons from entrepreneurship, and the journey of learning by doing. My goal is to provide value through code—whether it's through tools, content, or real-world software.

You might be interested in

Build an MCP Server in Next.js for Claude Code (Complete Guide)
Build an MCP Server in Next.js for Claude Code (Complete Guide)

30th November 2025

Build a Working MCP Server: Custom JSON-RPC Implementation
Build a Working MCP Server: Custom JSON-RPC Implementation

28th December 2025

Build a Production MCP Server in Next.js — Quick Guide
Build a Production MCP Server in Next.js — Quick Guide

30th November 2025

Build a Claude SEO Agent with Google Search Console MCP Integration
Build a Claude SEO Agent with Google Search Console MCP Integration

22nd December 2025

Building Secure Multi-User MCP Servers: Claude vs OpenAI's Authentication Gap
Building Secure Multi-User MCP Servers: Claude vs OpenAI's Authentication Gap

27th December 2025

Persist Google OAuth Refresh Tokens with Next.js & Redis
Persist Google OAuth Refresh Tokens with Next.js & Redis

21st December 2025

Table of Contents

  • Prerequisites
  • 1. The Email Infrastructure
  • 2. The Delivery Backend
  • 3. The MCP Tool Definition
  • The Complete MCP Server Series
On this page:
  • Prerequisites
  • 1. The Email Infrastructure
  • 2. The Delivery Backend
  • 3. The MCP Tool Definition
  • The Complete MCP Server Series
Build With Matija Logo

Build with Matija

Matija Žiberna

I turn scattered business knowledge into one usable system. End-to-end system architecture, AI integration, and development.

Quick Links

Payload CMS Websites
  • Bespoke AI Applications
  • Projects
  • How I Work
  • Blog
  • Get in Touch

    Have a project in mind? Let's discuss how we can help your business grow.

    Contact me →
    © 2026BuildWithMatija•Principal-led system architecture•All rights reserved