Skip to main content

What are inline images?

Inline images (also called embedded images) are images that appear directly within your email content, rather than as attachments. They’re referenced using a special cid: (Content-ID) URL scheme in your HTML, making them ideal for:
  • Email signatures: Company logos and branding
  • Transactional emails: Product images, receipts, invoices
  • Branded templates: Headers, footers, and design elements
  • Rich content: Diagrams, charts, and visual elements
Inline images are embedded in the email itself, so recipients see them immediately without downloading attachments—even with images disabled in some email clients.

How inline images work

  1. Attach an image with a unique Content-ID
  2. Reference the image in your HTML using cid:your-content-id
  3. Email clients display the image inline when rendering the email
The Content-ID acts as a unique identifier linking your HTML image references to the actual image data.

Sending inline images via API

Basic example

await lettermint.email
  .from('sender@yourdomain.com')
  .to('recipient@example.com')
  .subject('Welcome to our service')
  .html('<h1>Welcome!</h1><img src="cid:logo" alt="Company Logo">')
  .attach({
    filename: 'logo.png',
    content: 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==',
    content_id: 'logo'
  })
  .send();
The content field must be base64-encoded image data. Most programming languages provide built-in functions for base64 encoding files. Common image MIME types (PNG, JPG, GIF, WebP) are automatically detected from the file content.

Multiple inline images

You can embed multiple images by using different Content-IDs for each:
The total email size—including all inline images, attachments, HTML, and headers—must not exceed 25MB. See Limitations for details.
await lettermint.email
  .from('sender@yourdomain.com')
  .to('recipient@example.com')
  .subject('Your order receipt')
  .html('<div><img src="cid:header"><h1>Order Confirmation</h1><img src="cid:product-image"><p>Thank you for your order!</p><img src="cid:footer"></div>')
  .attach([
    {
      filename: 'header.png',
      content: '...',
      content_id: 'header'
    },
    {
      filename: 'product.jpg',
      content: '...',
      content_id: 'product-image'
    },
    {
      filename: 'footer.png',
      content: '...',
      content_id: 'footer'
    }
  ])
  .send();

Sending inline images via SMTP

When using SMTP, the email library handles Content-ID headers automatically for inline attachments.

Nodemailer (Node.js)

const nodemailer = require('nodemailer');
const fs = require('fs');

const transporter = nodemailer.createTransporter({
  host: 'smtp.lettermint.co',
  port: 587,
  auth: {
    user: 'lettermint',
    pass: 'your-api-token'
  }
});

await transporter.sendMail({
  from: 'sender@yourdomain.com',
  to: 'recipient@example.com',
  subject: 'Email with inline image',
  html: '<h1>Hello!</h1><img src="cid:unique-image-id" alt="Embedded Image">',
  attachments: [
    {
      filename: 'image.png',
      path: './path/to/image.png',
      cid: 'unique-image-id' // Content-ID reference
    }
  ]
});

PHPMailer (PHP)

<?php
use PHPMailer\PHPMailer\PHPMailer;

$mail = new PHPMailer(true);

$mail->isSMTP();
$mail->Host = 'smtp.lettermint.co';
$mail->SMTPAuth = true;
$mail->Username = 'lettermint';
$mail->Password = 'your-api-token';
$mail->Port = 587;

$mail->setFrom('sender@yourdomain.com');
$mail->addAddress('recipient@example.com');
$mail->Subject = 'Email with inline image';
$mail->isHTML(true);
$mail->Body = '<h1>Hello!</h1><img src="cid:unique-image-id" alt="Embedded Image">';

// Add inline image
$mail->addEmbeddedImage('/path/to/image.png', 'unique-image-id', 'image.png');

$mail->send();

Python (smtplib)

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage

msg = MIMEMultipart('related')
msg['From'] = 'sender@yourdomain.com'
msg['To'] = 'recipient@example.com'
msg['Subject'] = 'Email with inline image'

# HTML content
html = '<h1>Hello!</h1><img src="cid:unique-image-id" alt="Embedded Image">'
msg.attach(MIMEText(html, 'html'))

# Inline image
with open('image.png', 'rb') as img:
    image = MIMEImage(img.read())
    image.add_header('Content-ID', '<unique-image-id>')
    msg.attach(image)

# Send email
with smtplib.SMTP('smtp.lettermint.co', 587) as server:
    server.starttls()
    server.login('lettermint', 'your-api-token')
    server.send_message(msg)

Content-ID format requirements

Content-IDs must follow these rules:
  • Allowed characters: Letters (a-z, A-Z), numbers (0-9), dots (.), underscores (_), hyphens (-), and at-signs (@)
  • Pattern: Must match ^[a-zA-Z0-9._@-]+$
  • Maximum length: 255 characters
  • Automatic suffix: If your Content-ID doesn’t include @, Lettermint automatically appends @lm to ensure RFC compliance

Valid Content-ID examples

  • logo
  • company-logo
  • header_image
  • product.image.v2
  • banner@example.com
  • invoice-2024-01

Invalid Content-ID examples

  • logo image (spaces not allowed)
  • product#123 (# symbol not allowed)
  • header!image (! symbol not allowed)
  • logo/banner (/ symbol not allowed)
Use descriptive, semantic Content-IDs like company-logo or product-image instead of generic names like image1 or img. This makes your email templates more maintainable.

Troubleshooting

Check your Content-ID reference
  • Ensure your HTML uses cid:your-content-id (note the cid: prefix)
  • Verify the Content-ID in your attachment matches the HTML reference exactly (case-sensitive)
  • Don’t include angle brackets (<>) in your Content-ID when using the API
Verify base64 encoding
  • The content field must contain valid base64-encoded image data
  • Test your base64 string with an online decoder to ensure it’s valid
Check HTML syntax
<!-- Correct -->
<img src="cid:logo" alt="Logo">

<!-- Incorrect -->
<img src="logo" alt="Logo">
<img src="cid:<logo>" alt="Logo">
If your inline image also appears as a downloadable attachment:
  • Ensure you’re setting content_id in your API request
  • For SMTP, verify your email library supports inline attachments (check library-specific documentation)
If you receive validation errors:
  • Remove special characters except dots, underscores, hyphens, and @
  • Keep Content-IDs under 255 characters
  • Use only alphanumeric characters if unsure

Best practices

  1. Use descriptive Content-IDs: Choose meaningful names that describe the image’s purpose
  2. Optimize image sizes: Keep images small to reduce email size and improve deliverability
  3. Provide alt text: Always include alt attributes for accessibility and when images are blocked
  4. Test across email clients: Different email clients handle inline images differently—test thoroughly
  5. Consider fallbacks: Some email clients block images by default—design emails that work without them
  • Limitations — Email size limits (25MB) and blocked file types
  • Tags — Organize and categorize your emails
  • Webhook events — Track delivery and engagement for emails with inline images