smail/email

Write HTML compliant emails with peace of mind, like Lustre ๐Ÿ˜Œ.

smail is a library for composing HTML emails in Gleam. It handles all the quirks of email client rendering (Outlook MSO, Yahoo, AOL, Apple Mail, etc.) so you can focus on content rather than compatibility.

If you need something not covered by this module โ€” such as a plain table layout or inline <span> elements โ€” the lower-level smail/html module is available, though you will have to handle email client compatibility yourself.

Once your email is composed, use the rendering functions to produce the final output:

Types

A CSS generic or named fallback font family.

pub type FallbackFont {
  Arial
  Helvetica
  Verdana
  Georgia
  TimesNewRoman
  Serif
  SansSerif
  Monospace
  Cursive
  Fantasy
  CustomFallback(String)
}

Constructors

  • Arial
  • Helvetica
  • Verdana
  • Georgia
  • TimesNewRoman
  • Serif
  • SansSerif
  • Monospace
  • Cursive
  • Fantasy
  • CustomFallback(String)

The format of a web font file, used in the src: declaration of @font-face.

pub type FontFormat {
  Woff
  Woff2
  TrueType
  OpenType
  EmbeddedOpenType
  Svg
}

Constructors

  • Woff
  • Woff2
  • TrueType
  • OpenType
  • EmbeddedOpenType
  • Svg
pub type FontParams {
  FontParams
}

Constructors

  • FontParams

The CSS font-style value for a web font.

pub type FontStyle {
  StyleNormal
  StyleItalic
  StyleOblique
}

Constructors

  • StyleNormal
  • StyleItalic
  • StyleOblique

The CSS font-weight value for a web font.

pub type FontWeight {
  WeightNormal
  WeightBold
  WeightBolder
  WeightLighter
  Weight100
  Weight200
  Weight300
  Weight400
  Weight500
  Weight600
  Weight700
  Weight800
  Weight900
}

Constructors

  • WeightNormal
  • WeightBold
  • WeightBolder
  • WeightLighter
  • Weight100
  • Weight200
  • Weight300
  • Weight400
  • Weight500
  • Weight600
  • Weight700
  • Weight800
  • Weight900
pub type PlainTextConfig {
  PlainTextConfig(wrap_column: Int, enable_wrapping: Bool)
}

Constructors

  • PlainTextConfig(wrap_column: Int, enable_wrapping: Bool)

A remote web font to load via @font-face.

pub type WebFont {
  WebFont(url: String, format: FontFormat)
}

Constructors

Values

pub fn advanced_to_plain_text(
  el: html.Element,
  config: PlainTextConfig,
) -> String

Like to_plain_text but accepts a PlainTextConfig to control the column at which lines are wrapped and whether wrapping is enabled at all.

Example

import smail/email
import smail/html

email.html([], [
  email.head([], []),
  email.body([], [html.text("Hello!")]),
])
|> email.advanced_to_plain_text(email.PlainTextConfig(
  wrap_column: 80,
  enable_wrapping: True,
))
pub fn body(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render the email <body> element with cross-client compatibility fixes.

Example

import smail/email
import smail/html
import smail/style

email.body(
  [style.background_color("#f6f6f6"), style.padding("20px 0")],
  [html.text("Email content here")],
)
pub fn button(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render a clickable button compatible with Outlook (MSO) and modern email clients.

Example

import smail/attribute
import smail/email
import smail/html
import smail/style

email.button(
  [
    style.background_color("#000"),
    style.color("#fff"),
    style.padding("12px 24px"),
    attribute.href("https://example.com"),
  ],
  [html.text("Click me")],
)
pub fn center(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render a horizontally centered wrapper.

Example

import smail/attribute
import smail/email
import smail/html
import smail/style

email.center([], [
  email.button(
    [
      style.background_color("#000"),
      style.padding("12px 24px"),
      attribute.href("https://example.com"),
    ],
    [html.text("Get started")],
  ),
])
pub fn column(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render a column cell inside a row.

Example

import smail/attribute
import smail/email
import smail/html

email.row([], [
  email.column([attribute.width("50%")], [
    html.text("Left"),
  ]),
  email.column([attribute.width("50%")], [
    html.text("Right"),
  ]),
])
pub fn container(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render a centered email container with a maximum width of 600 px (37.5 em).

Example

import smail/email
import smail/html

email.body([], [
  email.container([], [
    html.text("Centered content, max 600px wide"),
  ]),
])
pub fn font(
  family font_family: String,
  fallback_family fallback_font_family: List(FallbackFont),
  web_font web_font: option.Option(WebFont),
  weight font_weight: option.Option(FontWeight),
  style font_style: option.Option(FontStyle),
) -> html.Element

Generate a <style> element that declares a custom web font and applies it globally.

Example

import gleam/option
import smail/email

email.font(
  family: "Josefin Sans",
  fallback_family: [email.Verdana, email.SansSerif],
  web_font: option.Some(email.WebFont(
    url: "https://fonts.gstatic.com/s/josefinsans/v32/Qw3aZQNVED7rKGKxtqIqX5EUDXx4.woff2",
    format: email.Woff2,
  )),
  weight: option.None,
  style: option.None,
)
pub fn h1(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render an <h1> heading with email-safe default styles.

pub fn h2(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render an <h2> heading with email-safe default styles.

pub fn h3(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render an <h3> heading with email-safe default styles.

pub fn head(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render the <head> element with email-required meta tags prepended.

Automatically inserts two meta tags before any provided children:

  • Content-Type: text/html; charset=UTF-8 โ€” ensures correct character encoding.
  • x-apple-disable-message-reformatting โ€” prevents Apple Mail from resizing or reformatting the email layout on iOS devices.

Example

import smail/attribute
import smail/email
import smail/html

email.head([], [
  html.meta([
    attribute.name("color-scheme"),
    attribute.content("light"),
  ]),
])
pub fn hr(attrs: List(attribute.Attribute)) -> html.Element

Render a horizontal rule <hr> styled as a thin separator line.

Example

import smail/email
import smail/html

email.section([], [
  email.paragraph([], [html.text("Above the line")]),
  email.hr([]),
  email.paragraph([], [html.text("Below the line")]),
])
pub fn html(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render the root <html> element.

Thin wrapper around smail/html.html.

Example

import smail/email

email.html([], [
  email.head([], []),
  email.body([], []),
])
pub fn img(attrs: List(attribute.Attribute)) -> html.Element

Render an <img> element with email-safe default styles.

Example

import smail/attribute
import smail/email

email.img([
  attribute.src("https://example.com/logo.png"),
  attribute.alt("Company logo"),
  attribute.width(200),
])
pub fn link(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render an <a> link with email-safe default styles.

Example

import smail/attribute
import smail/email
import smail/html

email.link(
  [attribute.href("https://example.com")],
  [html.text("Visit our website")],
)
pub fn paragraph(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render a paragraph <p> with email-safe default typography.

Example

import smail/email
import smail/html

email.paragraph([], [
  html.text("Your order has been confirmed."),
])
pub fn preview(text: String) -> html.Element

Render a hidden preview text node shown in email client inbox previews.

Example

import smail/email

email.html([], [
  email.head([], []),
  email.body([], [
    email.preview("Your order #1234 has been shipped!"),
    email.container([], []),
  ]),
])
pub fn row(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render a horizontal row used for multi-column layouts.

Example

import smail/email
import smail/html

email.row([], [
  email.column([], [html.text("Left column")]),
  email.column([], [html.text("Right column")]),
])
pub fn section(
  attrs: List(attribute.Attribute),
  children: List(html.Element),
) -> html.Element

Render a full-width layout section.

Example

import smail/email
import smail/html

email.container([], [
  email.section([], [
    email.paragraph([], [html.text("First section")]),
  ]),
  email.section([], [
    email.paragraph([], [html.text("Second section")]),
  ]),
])
pub fn to_html(el: html.Element) -> String

Converts an element to an HTML email.

Example

import smail/email
import smail/html

email.html([], [
  email.head([], []),
  email.body([], [html.text("Hello!")]),
])
|> email.to_html
pub fn to_plain_text(el: html.Element) -> String

Renders an element tree to a plain text string. Lines are wrapped at 72 characters by default.

Use advanced_to_plain_text to customise the wrapping behaviour.

Example

import smail/email
import smail/html

email.html([], [
  email.head([], []),
  email.body([], [html.text("Hello!")]),
])
|> email.to_plain_text
โœจ Search Document