Skip to main content

Inkletter

GitHub Repo CI PyPI version License: MIT

Write your emails like prose, send them like a pro.

Inkletter turns plain Markdown files into beautiful, responsive MJML and HTML email layouts, ready to be previewed, shared or sent to the world.

Why Inkletter?

Because writing HTML emails by hand is like ironing socks: pointless and painful.

With Inkletter, you write your content in Markdown (like a decent human being), and it becomes a gorgeous, mobile-friendly HTML email powered by MJML.

Features

  • Markdown to MJML or to final responsive HTML, in one command
  • Seven built-in themes, or your own theme in a small TOML file
  • Live preview in your browser, with a device simulator (iPhone, iPad, desktop)
  • Clean Python API if you'd rather script it
  • Runs entirely on your machine, no account, no vendor lock-in

Installation

Python 3.10+ required.

pip install inkletter

Or for development:

git clone https://github.com/lpauloin/Inkletter.git
cd Inkletter
pip install -e .

Usage

Preview a Markdown file as a responsive email

inkletter preview newsletter.md

Opens a split view in your browser: your Markdown, the generated MJML, and the rendered email in a device simulator.

Convert to HTML

inkletter md2html newsletter.md -o newsletter.html --view

Writes the final email HTML, and opens it in your browser with --view.

Export the raw MJML

inkletter md2mjml newsletter.md -o newsletter.mjml

Without -o, the MJML is printed to stdout, ready to be piped anywhere.

Image layout

Layout is driven by plain CommonMark structure — no custom syntax, the same file stays clean in any Markdown editor (and reusable for other channels):

  • A paragraph made only of images becomes a row of side-by-side columns (up to 4 on one row, more wrap into rows of 3):

    ![Left view](left.png) ![Right view](right.png)
    
  • A paragraph starting (or ending) with a single image beside text becomes a media object — image next to its text, 30/70 by default. Put the image last to place it on the right:

    ![Portrait](jean.png) Jean joined the team this week.
    He will own the rendering platform.
    

On mobile both patterns stack, image on top. Ratios, spacing and behaviour are tuned in the [images] theme section below — including text_layout = "stacked" to disable media-object columns entirely.

Theming

Every command accepts --theme with a preset name or a theme file, and --no-theme for bare, unstyled MJML:

inkletter md2html newsletter.md --theme dark
inkletter md2html newsletter.md --theme mytheme.toml

Built-in presets

Preset Mood
default Clean and neutral — Helvetica, gray text, blue links
dark Slate night mode — light text, Trebuchet MS headings
crystal Airy and elegant — Palatino headings, cold blue accents
blue Corporate and trustworthy — Tahoma text, Trebuchet MS headings
green Organic and editorial — Georgia throughout
red Bold and editorial — Georgia headings over Helvetica text
yellow Warm and friendly — Verdana text, Trebuchet MS headings

Here is each preset rendered on desktop and on a 375px mobile screen:

The built-in themes on desktop and mobile

Write your own

A theme file is partial — set only what you want to change, everything else keeps the default look:

[layout]
width = "640px"

[text]
font_family = "Georgia, serif"

[links]
color = "#c0392b"
underline = false
Section Keys
[layout] width, background_color, content_background_color, section_padding
[text] font_family, font_size, line_height, color
[headings] font_family, color, font_weight, h1_size, h2_size, h3_size
[links] color, underline
[code] font_family, background_color, color
[quote] color, border_color, font_style
[divider] color, width
[table] border_color, cell_padding, header_color, header_background_color
[images] align, row_gap, border_radius, text_layout, media_ratio

Any unknown section or key fails loudly, with the list of valid ones.

From Python

Same defaults, same presets, plus optional named color palettes:

from inkletter.colors import Blue
from inkletter.md_to_html import parse_markdown_to_html
from inkletter.theme import Links, Text, Theme

theme = Theme(text=Text(font_family="Georgia, serif"), links=Links(color=Blue.DARK))
html = parse_markdown_to_html(markdown, theme=theme)

Samples

Contributing

French or not, you are welcome to contribute. Fork it, branch it, test it, PR it — with love.

pip install -r requirements-test.txt
pytest

Every push and pull request runs through the GitHub Actions CI on Python 3.10 to 3.13.

License

MIT — but don't forget to say "merci" 😉

Made with ❤️ and markdown in France.

Metadata

Release files for inkletter 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for inkletter 1.1.0
File Size Uploaded
inkletter-1.1.0.tar.gz 26.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for inkletter 1.1.0
File Interpreter ABI Platform
inkletter-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 50.1 kB

Release files / inkletter-1.1.0.tar.gz

Download URL inkletter-1.1.0.tar.gz
Size 26.0 kB
Tags Source
SHA-256 checksum
How to use checksums
d2087bf9fddd41ae1c9e185b7ebf7a084d4a865a8ed4ce21110e813cdb6d4f45
BLAKE2b-256 checksum
How to use checksums
9139602e6bd6c2cd2d91ee29da36cbb062a66061cf6737d3e58bd39d20c97641
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release files / inkletter-1.1.0-py3-none-any.whl

Download URL inkletter-1.1.0-py3-none-any.whl
Size 24.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aeb4cc9bbd1d6ddd0d52af1779722f985cf699dd727b302117190915c6148864
BLAKE2b-256 checksum
How to use checksums
714272b2eb43c0f1e878bb2868d7bf6216e14bb1a8b598e4f2a5bc8813080bd4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release history Release notifications | RSS feed

3.4.0

2 release files

3.3.0

2 release files

3.2.0

2 release files

3.1.0

2 release files

3.0.0

2 release files

2.2.0

2 release files

2.1.0

2 release files

2.0.0

2 release files

This release

1.1.0 This release

2 release files

1.0.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page