Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/buttondown/cli/llms.txt

Use this file to discover all available pages before exploring further.

Emails in the Buttondown CLI are stored as Markdown files with YAML frontmatter, providing a clean and version-control-friendly format for your newsletter content.

File Format

Each email file follows this structure:
---
id: abc123xyz
subject: Welcome to my newsletter!
email_type: public
status: published
slug: welcome-email
publish_date: 2024-01-15T10:00:00Z
description: A warm welcome to new subscribers
---

# Welcome!

Thanks for subscribing to my newsletter.

![Header image](../media/welcome-header.png)

I'm excited to have you here!

Frontmatter Fields

The frontmatter section (between the --- delimiters) contains metadata about the email. The CLI supports the following fields, defined in src/sync/emails.ts:41-57:

Core Fields

id
string
required
Unique identifier for the email. Set by Buttondown when the email is created. Required for updating existing emails.
subject
string
required
The email subject line. This is what subscribers see in their inbox.
email_type
string
default:"public"
The type of email. Options:
  • public - Regular newsletter email (default)
  • private - Subscriber-only content
  • premium - Premium subscriber content
status
string
Publication status. Options:
  • draft - Not yet sent
  • scheduled - Scheduled for future sending
  • published - Already sent to subscribers
slug
string
URL-friendly identifier for the email. Used in web archives and for the filename when syncing.
publish_date
string (ISO 8601)
When the email was or will be published. Format: YYYY-MM-DDTHH:mm:ssZExample: 2024-01-15T10:00:00Z

Optional Fields

description
string
A brief description of the email content. Used for SEO and previews.
image
string (URL)
Featured image URL for the email. Displayed in web archives and social shares.
canonical_url
string (URL)
Canonical URL if this email was originally published elsewhere.
secondary_id
string
Secondary identifier for the email, if needed for external systems.
metadata
object
Custom metadata as key-value pairs. Useful for storing additional data.
metadata:
  category: tutorial
  reading_time: 5
Whether this email should be featured in your archive.
commenting_mode
string
default:"enabled"
Controls comments on the email. Options:
  • enabled - Comments allowed (default)
  • disabled - Comments not allowed
filters
object
Subscriber filters for targeted sending.
filters:
  predicate: and
  filters: []
  groups: []
Array of related email IDs.
related_email_ids:
  - email_123
  - email_456

Email Body

The content after the second --- delimiter is the email body, written in Markdown.

Supported Markdown

Buttondown supports standard Markdown syntax:
  • Headers: # H1, ## H2, ### H3
  • Bold: **bold text**
  • Italic: *italic text*
  • Links: [link text](https://example.com)
  • Images: ![alt text](image-url)
  • Lists: Both ordered (1. Item) and unordered (- Item)
  • Code: Inline `code` and code blocks
  • Blockquotes: > Quote

Image References

The CLI handles image references in a special way to support local development:

Relative Paths (Local)

When working locally, reference images using relative paths:
![Chart showing growth](../media/growth-chart.png)

Absolute URLs (Remote)

When pushing to Buttondown, the CLI automatically converts relative paths to absolute URLs:
![Chart showing growth](https://buttondown.s3.amazonaws.com/images/abc123.png)
You don’t need to manually convert between relative and absolute paths. The CLI handles this automatically during push and pull operations.

Serialization and Deserialization

The CLI includes functions to convert between Buttondown API format and Markdown files.

Deserialize (API → Markdown)

From src/sync/emails.ts:76-122, the deserialize function:
  1. Splits content by --- delimiters
  2. Parses YAML frontmatter
  3. Extracts email body
  4. Validates required fields
export function deserialize(content: string): {
  email: Partial<Email>;
  isValid: boolean;
  error?: string;
}

Serialize (Markdown → API)

From src/sync/emails.ts:132-163, the serialize function:
  1. Separates frontmatter from body
  2. Filters out empty/default values
  3. Generates clean YAML
  4. Combines into final Markdown format
export function serialize(email: Partial<Email & FrontMatterFields>): string

Default Values

The CLI omits fields with default values to keep files clean. Default values from src/sync/emails.ts:59-71:
const FRONT_MATTER_FIELD_TO_DEFAULT_VALUE = {
  email_type: "public",
  featured: false,
  commenting_mode: "enabled",
  filters: {
    filters: [],
    groups: [],
    predicate: "and",
  },
  related_email_ids: [],
};

Creating New Emails

You can create email files in two ways:

1. Using the CLI

buttondown create --title="My New Email"
This creates a new draft email locally with minimal frontmatter.

2. Manual Creation

Create a new .md file in the emails/ directory:
---
subject: My Manually Created Email
status: draft
email_type: public
---

Your email content here...
When manually creating emails, omit the id field. Buttondown will generate one when you first push the email.

Editing Emails

Edit email files directly in your favorite text editor:
  1. Open the .md file
  2. Modify frontmatter fields or body content
  3. Save the file
  4. Run buttondown push to sync changes to Buttondown
The CLI only uploads emails that have changed, so you can safely edit multiple files and push them all at once.

Special Handling

Editor Mode Sigil

The CLI adds a special comment to email bodies when pushing to Buttondown:
<!-- buttondown-editor-mode: plaintext -->
This tells Buttondown to treat the content as Markdown. The CLI automatically removes this when pulling emails down.

Image Path Conversion

The CLI automatically handles image path conversions:
  • Pull: Converts https://buttondown.s3.amazonaws.com/images/abc123.png../media/header.png
  • Push: Converts ../media/header.pnghttps://buttondown.s3.amazonaws.com/images/abc123.png
This is done by maintaining a mapping in .buttondown.json (see Sync Workflow).