To use Brevo (formerly Sendinblue) with V0 by Vercel, create a Next.js API route that calls the Brevo API to send transactional emails, manage contacts, and trigger campaign automations. Store your Brevo API key as a server-only environment variable in Vercel. V0 generates the email form UI; your API route handles the secure server-side Brevo SDK calls.
Transactional and Marketing Email in One V0 Integration
Most email tools force you to choose: either you get a great marketing platform for campaigns and newsletters, or you get a transactional email service for password resets and order confirmations. Brevo is one of the few platforms that does both well in a single API. For developers building with V0, this means you can send a welcome email when someone signs up, add them to a nurture sequence, and track opens and clicks — all through the same Brevo API key and the same Next.js integration.
The integration architecture is straightforward: V0 generates your email capture forms, contact pages, or trigger buttons as React components. A Next.js API route handles the actual Brevo API calls server-side, which keeps your API key secure. The Brevo Node.js SDK (@getbrevo/brevo) simplifies the API surface with TypeScript support, letting you send emails, manage contacts, and list operations with just a few lines of code.
One advantage Brevo has over dedicated transactional email services like Mailgun is the contact management and automation layer. When your V0 app sends an email, Brevo can simultaneously add the recipient to a list, tag them with attributes, and enroll them in an automation sequence — turning a single API call into a full marketing workflow. This tutorial covers the complete integration from generating the form UI in V0 to deploying a working email system on Vercel.
Integration method
V0 generates the frontend form or email trigger UI. A Next.js API route at app/api/email/route.ts handles the Brevo API call server-side using the @getbrevo/brevo SDK with your secret API key. The client component POSTs form data to the API route, which constructs the email payload and sends it via Brevo's SMTP or Transactional API — your API key never touches the browser.
Prerequisites
- A V0 account at v0.dev with an active project
- A Brevo account at brevo.com (free tier available, includes 300 emails/day)
- Your Brevo API key from Brevo Dashboard → Account → SMTP & API → API Keys
- A Vercel account for deployment and environment variable management
- Node.js knowledge for understanding API route structure (beginner-level is fine)
Step-by-step guide
Generate the Email Form UI in V0
Generate the Email Form UI in V0
Open V0 and describe the email capture or contact form you need. Brevo works with any form that collects an email address — contact forms, newsletter signups, waitlist pages, or trigger buttons for transactional emails. The key is to design the component so it handles form state, loading, success, and error states cleanly. When prompting V0, specify that the form should POST to a specific API route path (e.g., /api/contact or /api/subscribe). Ask V0 to include a loading spinner during submission and a success message after. This is important because Brevo API calls are asynchronous and take a moment to complete. Also ask V0 to handle the case where the API returns an error — a visible error message prevents silent failures from confusing users. In Design Mode, adjust the visual style to match your brand. Then inspect the Code panel to see how V0 wired up the form's onSubmit handler — you'll later connect this to your Brevo API route. Look at the fetch call V0 generated: it should POST the form data as JSON to your API endpoint. If V0 generated a form without an API call, use the chat to add 'Make the form submit to /api/contact via a POST fetch request with the form data as JSON'.
Create a contact form with fields for first name, email address, and message. The form should POST to /api/contact with { firstName, email, message } as JSON. Show a loading spinner on the submit button during submission. After success, replace the form with a message saying 'Thanks! We received your message and will reply within 24 hours.' Show an inline red error message if the API returns an error.
Paste this in V0 chat
Pro tip: Ask V0 to generate the success and error states as separate JSX blocks that conditionally render — this makes the component cleaner and easier to debug than inline conditional styling.
Expected result: A React form component renders with proper loading, success, and error states. The form's onSubmit handler calls fetch('/api/contact', { method: 'POST', body: JSON.stringify(formData) }) and handles the response.
Install the Brevo SDK and Create the API Route
Install the Brevo SDK and Create the API Route
The official Brevo Node.js SDK is @getbrevo/brevo (not the older sib-api-v3-sdk). Install it by adding it to your package.json. Then create your Next.js API route at app/api/contact/route.ts (or app/api/subscribe/route.ts — match whatever path you used in your V0 component). The App Router API route exports an async POST function that reads the request body, initializes the Brevo API client with your secret key, and calls the appropriate Brevo API method. For sending a transactional email, use the TransactionalEmailsApi class and its sendTransacEmail method. For adding a contact to a list, use the ContactsApi class and its createContact method. The Brevo SDK uses a configuration object where you set the API key via setApiKey. One important pattern: always validate the incoming request body before calling Brevo. Check that the email field is present and is a valid email format. Return a 400 error if validation fails rather than sending malformed data to Brevo. Also wrap the Brevo SDK call in a try/catch block to handle API errors gracefully — Brevo returns specific error messages for things like invalid email addresses, blocked contacts, or rate limits, and surfacing these to your frontend helps with debugging.
Create a Next.js API route at app/api/contact/route.ts that receives a POST request with { firstName, email, message }. Import TransactionalEmailsApi and SendSmtpEmail from @getbrevo/brevo. Configure the API client with process.env.BREVO_API_KEY. Send a transactional email to the site owner at process.env.CONTACT_EMAIL with the subject 'New Contact Form Submission' and the message details in the email body. Return { success: true } on success or { error: message } on failure.
Paste this in V0 chat
1import { NextRequest, NextResponse } from 'next/server';2import * as Brevo from '@getbrevo/brevo';34export async function POST(req: NextRequest) {5 try {6 const { firstName, email, message } = await req.json();78 if (!email || !email.includes('@')) {9 return NextResponse.json({ error: 'Valid email is required' }, { status: 400 });10 }1112 const transactionalEmailsApi = new Brevo.TransactionalEmailsApi();13 transactionalEmailsApi.setApiKey(14 Brevo.TransactionalEmailsApiApiKeys.apiKey,15 process.env.BREVO_API_KEY!16 );1718 const sendSmtpEmail = new Brevo.SendSmtpEmail();19 sendSmtpEmail.subject = `New Contact: ${firstName || 'Anonymous'}`;20 sendSmtpEmail.htmlContent = `21 <h2>New contact form submission</h2>22 <p><strong>Name:</strong> ${firstName}</p>23 <p><strong>Email:</strong> ${email}</p>24 <p><strong>Message:</strong> ${message}</p>25 `;26 sendSmtpEmail.sender = { name: 'Contact Form', email: process.env.SENDER_EMAIL! };27 sendSmtpEmail.to = [{ email: process.env.CONTACT_EMAIL!, name: 'Site Owner' }];28 sendSmtpEmail.replyTo = { email, name: firstName };2930 await transactionalEmailsApi.sendTransacEmail(sendSmtpEmail);3132 return NextResponse.json({ success: true });33 } catch (error: unknown) {34 const message = error instanceof Error ? error.message : 'Failed to send email';35 console.error('Brevo error:', error);36 return NextResponse.json({ error: message }, { status: 500 });37 }38}Pro tip: The replyTo field lets you set the visitor's email as the reply-to address — so when you reply to the notification email in your inbox, it goes directly to the person who filled out the form.
Expected result: The API route at /api/contact accepts POST requests and sends a transactional email via Brevo. The route returns { success: true } on success or an error message on failure, with appropriate HTTP status codes.
Add Contact List Subscription (Optional)
Add Contact List Subscription (Optional)
If you want to also add the contact to a Brevo list for follow-up marketing emails or newsletters, extend your API route to call ContactsApi.createContact after sending the transactional email. This is where Brevo's dual transactional-and-marketing capability shines — in one API call you send the confirmation email AND add the person to your CRM. To find your Brevo list IDs, go to Brevo Dashboard → Contacts → Lists — each list shows its numeric ID in the URL (e.g., contacts.brevo.com/lists/5 means list ID 5). The createContact method accepts an email, optional attributes (any custom fields you've defined in Brevo like FIRSTNAME, SOURCE, SIGNUP_DATE), and a listIds array. Set updateEnabled to true so re-subscriptions update the existing contact rather than returning a duplicate error. Brevo's double opt-in feature (also called confirmed opt-in or COI) can be enabled per list — if enabled, Brevo automatically sends a confirmation email and only adds the contact after they click the confirmation link. You don't need to handle this in code; Brevo manages the confirmation flow. One thing to watch: Brevo may return a 4xx error if the contact already exists and updateEnabled is false. Always set updateEnabled: true for signup forms to handle repeat submissions gracefully.
Update app/api/contact/route.ts to also call Brevo's ContactsApi.createContact with the visitor's email and firstName after sending the notification email. Add them to list ID from process.env.BREVO_LIST_ID. Set updateEnabled to true and add attributes { FIRSTNAME: firstName, SOURCE: 'contact-form' }. Wrap this in a separate try/catch so a list subscription failure doesn't prevent the main email from being sent.
Paste this in V0 chat
1import * as Brevo from '@getbrevo/brevo';23// Add to your existing route handler after the email send:4async function addToBrevoList(email: string, firstName: string) {5 const contactsApi = new Brevo.ContactsApi();6 contactsApi.setApiKey(7 Brevo.ContactsApiApiKeys.apiKey,8 process.env.BREVO_API_KEY!9 );1011 const createContact = new Brevo.CreateContact();12 createContact.email = email;13 createContact.attributes = {14 FIRSTNAME: firstName,15 SOURCE: 'contact-form',16 };17 createContact.listIds = [parseInt(process.env.BREVO_LIST_ID || '0')];18 createContact.updateEnabled = true;1920 await contactsApi.createContact(createContact);21}Pro tip: Keep the list subscription in a separate try/catch from the email send. A contact who's already unsubscribed from your list will cause createContact to throw, but you still want to send them a confirmation email.
Expected result: New contacts are added to your Brevo list with custom attributes. Returning visitors update their existing contact record rather than causing a duplicate error. The Brevo Dashboard → Contacts shows new entries after form submissions.
Configure Environment Variables in Vercel
Configure Environment Variables in Vercel
Brevo requires two required environment variables and two optional ones. The required ones are BREVO_API_KEY (your secret key from Brevo Dashboard → Account → SMTP & API → API Keys — starts with 'xkeysib-') and SENDER_EMAIL (a verified sender address — you must verify this in Brevo under Senders & IP → Senders before emails will send). The optional ones are CONTACT_EMAIL (where you want to receive contact form notifications — can be the same as SENDER_EMAIL or different) and BREVO_LIST_ID (the numeric ID of the list you want subscribers added to). To add variables in Vercel, open your project in the Vercel Dashboard, go to Settings → Environment Variables, and add each key. Make sure to add them to both the Production and Preview environments. The BREVO_API_KEY must not have a NEXT_PUBLIC_ prefix — it is server-only and should never reach the browser. After adding variables, you need to trigger a redeployment for them to take effect. The easiest way is to push a small code change or click Redeploy in Vercel Dashboard → Deployments → the latest deployment → Redeploy. To test locally, add the same variables to your .env.local file (never commit this file). After the deployment succeeds, submit your contact form and check your inbox — emails can take up to 2 minutes to arrive on Brevo's free tier. Check the Brevo Dashboard → Transactional → Email Logs to confirm the API received and sent the request, even if your inbox hasn't received it yet.
1# .env.local — never commit this file to git2# Brevo (Sendinblue) API credentials3BREVO_API_KEY=xkeysib-your-actual-api-key-here45# Verified sender email (must be verified in Brevo Dashboard → Senders)6SENDER_EMAIL=hello@yourdomain.com78# Where to receive contact form notifications9CONTACT_EMAIL=you@yourdomain.com1011# Optional: Brevo list ID for newsletter subscriptions (find in Brevo → Contacts → Lists URL)12BREVO_LIST_ID=5Pro tip: Brevo's free plan limits you to 300 emails/day and requires email verification via a confirmation link sent to SENDER_EMAIL. Complete this verification in Brevo Dashboard → Senders & IP → Senders before testing — unverified senders result in silent failures.
Expected result: All four environment variables are set in Vercel Dashboard under Settings → Environment Variables. The deployed app sends transactional emails via Brevo, and the Brevo Dashboard → Transactional → Email Logs shows successful sends.
Test the Integration and Use Brevo Templates
Test the Integration and Use Brevo Templates
Once your basic email API route is working, level it up by using Brevo email templates instead of inline HTML. Templates are designed in Brevo's drag-and-drop editor and called by template ID from your API route — this separates email design from your code, letting non-developers update email content without touching the Next.js app. To use a template: go to Brevo Dashboard → Email → Templates → Create a template. Design your email in the template editor and add dynamic variables using double curly braces: {{ params.FIRSTNAME }}, {{ params.ORDER_TOTAL }}, etc. Save and activate the template, then copy its numeric ID from the templates list. In your API route, replace the htmlContent field with templateId and params. The params object maps to the {{ params.* }} variables in your template. This pattern is especially powerful for order confirmations, welcome sequences, and password resets — the template controls the design while your Next.js code only sends the data. After deploying, test the full flow from the live URL on Vercel. For complex automation workflows like multi-step onboarding sequences or re-engagement campaigns, RapidDev can help you structure the Brevo API integration alongside your V0 app's backend logic.
Update app/api/contact/route.ts to use a Brevo email template instead of inline HTML. Replace the htmlContent property with templateId set to parseInt(process.env.BREVO_TEMPLATE_ID!) and add a params object with { FIRSTNAME: firstName, MESSAGE: message, REPLY_EMAIL: email }. Keep all other configuration the same.
Paste this in V0 chat
1// Using a Brevo template instead of inline HTML2const sendSmtpEmail = new Brevo.SendSmtpEmail();3sendSmtpEmail.to = [{ email: process.env.CONTACT_EMAIL!, name: 'Site Owner' }];4sendSmtpEmail.sender = { name: 'My App', email: process.env.SENDER_EMAIL! };5sendSmtpEmail.templateId = parseInt(process.env.BREVO_TEMPLATE_ID || '0');6sendSmtpEmail.params = {7 FIRSTNAME: firstName,8 MESSAGE: message,9 REPLY_EMAIL: email,10 SUBMISSION_DATE: new Date().toLocaleDateString('en-US'),11};1213await transactionalEmailsApi.sendTransacEmail(sendSmtpEmail);Pro tip: Always test templates in Brevo's preview mode with sample params before using them in production. Template rendering errors show up as blank emails — the API call succeeds but the email content is empty.
Expected result: The contact form sends a branded template email with dynamic variables populated from the form data. The Brevo template editor shows the send in its analytics dashboard with open tracking.
Common use cases
Contact Form with Transactional Confirmation Email
Build a contact page where visitors submit their name, email, and message. On submission, your API route sends a confirmation email to the visitor via Brevo's transactional API and notifies your team. Brevo's free tier includes 300 emails/day, making it ideal for contact forms on V0-generated landing pages.
Create a contact form page with fields for name, email, and message. Add a submit button that POSTs to /api/contact. Show a success state with a green checkmark and 'We'll get back to you within 24 hours' message after successful submission. Include loading state and error handling.
Copy this prompt to try it in V0
Newsletter Signup with Brevo List Management
Add a newsletter signup form to your V0 app that subscribes visitors to a Brevo contact list. The API route adds the contact with custom attributes (signup source, date) and optionally triggers a double opt-in confirmation email. This pattern is common on landing pages and SaaS waitlists.
Build a newsletter signup section with an email input and 'Subscribe' button. On success, show a toast notification saying 'Check your email to confirm your subscription'. Style it with a dark background and subtle gradient. Include a small privacy note below the input.
Copy this prompt to try it in V0
Transactional Email for User Actions
Trigger personalized transactional emails when users take specific actions in your app — completing a purchase, resetting a password, or finishing onboarding. Brevo's template system lets you design branded emails in their editor and call them from your API route with dynamic variables like the user's name and order details.
Create an order confirmation page that displays a summary of items, total, and delivery estimate. Add a button to resend the confirmation email. The page should fetch order data from /api/orders/:id and call /api/email/order-confirmation to retrigger the Brevo template email.
Copy this prompt to try it in V0
Troubleshooting
API route returns 500 and logs show 'Unauthorized' or '401' from Brevo
Cause: The BREVO_API_KEY environment variable is missing, incorrectly named, or not yet deployed to the Vercel environment where the route is running.
Solution: Verify the variable is set in Vercel Dashboard → Settings → Environment Variables with the exact name BREVO_API_KEY (not SENDINBLUE_API_KEY or any other variant). After adding or changing it, redeploy your project — Vercel does not hot-reload environment variables.
API returns success but no email arrives in inbox
Cause: Either the sender email is not verified in Brevo, or the email was sent to spam/blocked by your email provider. Brevo silently accepts some requests even when there's a sender verification issue.
Solution: Check Brevo Dashboard → Transactional → Email Logs to see the delivery status. If the log shows 'softbounce' or 'blocked', verify your sender domain in Brevo Dashboard → Senders & IP → Domains. Add the Brevo SPF and DKIM records to your DNS provider to improve deliverability.
createContact throws 'Contact already exist' error
Cause: You are calling createContact for an email that already exists in Brevo and have not set updateEnabled to true.
Solution: Set updateEnabled: true on the CreateContact object. This tells Brevo to update the existing contact's attributes and list membership instead of returning an error. This is the correct behavior for signup forms that might be submitted multiple times.
1createContact.updateEnabled = true;Emails send in development but fail with 'Cannot read properties of undefined' in production
Cause: The SENDER_EMAIL or CONTACT_EMAIL environment variable is not set in Vercel's Production environment, even if it works locally via .env.local.
Solution: Open Vercel Dashboard → Settings → Environment Variables and confirm all four variables (BREVO_API_KEY, SENDER_EMAIL, CONTACT_EMAIL, and optionally BREVO_LIST_ID) are set for the Production environment specifically, not just Preview or Development.
Best practices
- Always store BREVO_API_KEY without a NEXT_PUBLIC_ prefix — it is a secret key that must only exist in server-side code and Vercel environment variables, never in the browser bundle
- Verify your sender email domain in Brevo Dashboard → Senders & IP → Domains by adding SPF, DKIM, and DMARC DNS records to improve deliverability and avoid landing in spam
- Use Brevo email templates instead of inline HTML strings in your API route — templates can be updated in Brevo's editor without redeploying your Next.js app
- Keep the transactional email send and contact list subscription in separate try/catch blocks so a failed list subscription doesn't block the confirmation email from sending
- Set updateEnabled: true on all createContact calls to handle users who re-submit forms without throwing duplicate contact errors
- Check Brevo Dashboard → Transactional → Email Logs after testing — the API call may succeed while the actual email delivery fails due to sender verification or spam filtering
- Use Brevo's double opt-in feature for newsletter subscriptions to comply with GDPR and reduce spam complaints — enable it per list in Brevo Dashboard → Contacts → Lists → Settings
Alternatives
Mailchimp is a better choice if your primary use case is marketing campaigns and audience segmentation rather than transactional email — it has a much larger template library and more advanced audience tools.
Mailgun is a better choice if you need high-volume transactional email with advanced deliverability features and detailed analytics, but without the built-in marketing campaign tools that Brevo includes.
SendGrid is a better choice for enterprise-scale transactional email with dedicated IP addresses and advanced suppression management, while Brevo's integrated CRM makes it easier to manage both transactional and marketing in one platform.
Frequently asked questions
Is Brevo the same as Sendinblue?
Yes — Sendinblue rebranded to Brevo in May 2023. The platform is identical; only the name changed. The npm package @getbrevo/brevo is the updated SDK, while the older sib-api-v3-sdk still works but is no longer maintained. The API endpoints and authentication are the same.
Does Brevo work with V0's free tier?
Yes. Brevo's free plan includes 300 transactional emails per day with no monthly limit on contacts, which is more than enough for development and low-traffic production apps. Vercel's Hobby plan supports the Next.js API routes needed for server-side Brevo calls. You will need to verify your sender email address on the free tier.
Can I send emails directly from a React component without an API route?
No — and you should never do this even if a library claims to support it. Calling the Brevo API directly from a React component would expose your API key in the browser's JavaScript bundle, where any visitor could extract it and use it to send spam from your account. Always proxy Brevo API calls through a Next.js API route.
What's the difference between Brevo's transactional and marketing email?
Transactional emails are triggered by user actions — form confirmations, password resets, order receipts — and are sent one-to-one in real time. Marketing emails are bulk sends to contact lists — newsletters, promotions, automated sequences. Brevo handles both through the same API key, which is its main advantage over tools that specialize in one or the other.
How do I handle Brevo unsubscribes in my Next.js app?
Brevo automatically manages unsubscribes for marketing emails — contacts who click the unsubscribe link are added to your blacklist and excluded from future sends. For transactional emails, Brevo does not apply unsubscribe suppression by default. You can configure this in Brevo Dashboard → SMTP & API → Unsubscriptions. Your app doesn't need to handle unsubscribes programmatically; Brevo manages the suppression list.
How do I test Brevo emails locally without sending real emails?
Add your .env.local with real Brevo credentials and use a test email address that you control. Brevo also offers an email preview feature in the Dashboard under Transactional → Email Logs where you can see a rendered preview of sent emails. For automated testing, consider using Brevo's test mode or a service like Mailtrap as an SMTP relay during development.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation