Brevo Base64 attachments and CID images
Adding a Base64 attachment to a Brevo transactional email does not by itself make that attachment an inline image. An HTML reference such as <img src="cid:logo001"> needs a matching Content-ID in the email's MIME structure.
The public transactional API schema checked on October 8, 2026, documents attachment url, content, and name fields. It does not expose a caller-controlled Content-ID field in that attachment object. Do not invent a cid or contentId field and assume it will work.
You can prepare a raw Base64 attachment with the Image to Base64 tool. For an image displayed inside the message, the example below uses an HTTPS image URL and keeps the Base64 file as an ordinary attachment.
What the transactional API documents
For POST /v3/smtp/email, Brevo documents two attachment sources: an absolute file URL, or Base64 content. When you provide content, also provide the filename in name.
These fields describe an attachment. They are not a documented way to bind an HTML cid: reference. A setting from another Brevo product or a different provider is not automatically part of this transactional endpoint's contract. If CID is essential to your delivery workflow, confirm the currently supported method with Brevo or use a provider that documents the required CID fields, such as the SendGrid inline-image API.
A hosted image plus a Base64 attachment
Save this as brevo-attachment.mjs. It requires Node.js 18 or later and a local logo.png. Set IMAGE_URL to a public HTTPS image you control. The default command prints JSON; adding --send makes an actual request.
import { readFile } from "node:fs/promises";
const imageUrl = new URL(process.env.IMAGE_URL || "https://example.com/logo.png");
if (imageUrl.protocol !== "https:") throw new Error("IMAGE_URL must use HTTPS");
const bytes = await readFile("logo.png");
const safeImageUrl = imageUrl.href.replaceAll("&", "&").replaceAll('"', """);
const payload = {
sender: { email: process.env.EMAIL_FROM || "sender@example.com" },
to: [{ email: process.env.EMAIL_TO || "recipient@example.com" }],
subject: "Image and attachment example",
htmlContent: `<p>Your image:</p><img src="${safeImageUrl}" alt="Company logo">`,
textContent: "This message includes a hosted image and a PNG attachment.",
attachment: [{ content: bytes.toString("base64"), name: "logo.png" }]
};
if (!process.argv.includes("--send")) {
console.log(JSON.stringify(payload, null, 2));
} else {
const key = process.env.BREVO_API_KEY;
if (!key || !process.env.EMAIL_FROM || !process.env.EMAIL_TO || !process.env.IMAGE_URL) {
throw new Error("Set BREVO_API_KEY, EMAIL_FROM, EMAIL_TO, and IMAGE_URL first.");
}
const response = await fetch("https://api.brevo.com/v3/smtp/email", {
method: "POST",
headers: { "api-key": key, "Content-Type": "application/json", "Accept": "application/json" },
body: JSON.stringify(payload)
});
const result = await response.json();
if (!response.ok) throw new Error(`Brevo request failed: ${JSON.stringify(result)}`);
console.log(result.messageId);
}
https://example.com/logo.png is a placeholder, not a working image asset. The real image must be reachable without your private login. Recipients' mail clients may block remote images until the user allows them. Keep credentials on your server, and test the intended clients before relying on the visual result.
Raw Base64 is not a data URI
The content field holds the encoded file bytes. Do not include data:image/png;base64, in that field, and do not Base64-encode a string that is already Base64. Use the API payload guide when converting between output shapes.
A browser can render a data URI even when an email client strips it. Switching the HTML source to a data URI is therefore not a reliable substitute for a supported inline-attachment workflow. The Outlook image guide covers this compatibility distinction.
Troubleshooting
The attachment arrives but cid:logo001 is blank. The attachment filename is not a Content-ID. The checked schema does not document a field that connects that CID to the attachment. Use a hosted image or confirm a supported CID method before relying on it.
The API rejects the attachment. Inspect raw Base64 versus data URI, the required filename, supported file types, and your current provider limits. Decode the value locally to confirm it contains the intended bytes.
The hosted image does not show. Check the final HTTPS URL without a login, then check the client's image-blocking policy. API acceptance is not proof of rendering.
FAQ
Does this prove that all Brevo email products lack CID support?
No. This guide describes the checked public transactional endpoint. Product capabilities and schemas can change.
Can I add a contentId property anyway?
That would depend on undocumented behavior. Use documented fields or get a supported method confirmed by Brevo.
Do I need Base64 for the hosted image?
No. The hosted image uses an HTTPS URL. Base64 is used separately for the ordinary attachment in this example.
Related guides
Compare SendGrid inline images, review Base64 API output shapes, and check Outlook rendering behavior.