Plain text
Every message carries a plain-text part in Message.Text, beside the HTML. lttr builds it from the compiled template, module by module, with github.com/sulv-io/lttr/render/text. It never strips tags from the HTML, so the text part reads as if someone had written it by hand: actions are labelled, tables line up, and the chrome is reduced to what a text reader needs.
Read a text part
This is the text part of the Quiet order email, byte for byte from testdata/golden/:
CARIBHUBS
ORDER CH-20417
On its way.
Kareem picked up your order at 2:14 pm and will reach Frigate Bay by
5:30 pm.
Track delivery:
https://caribhubs.com/orders/CH-20417
Confirmed ✓ > Packed ✓ > [On its way] > Delivered
Mahogany serving board x1 ....... EC$185
Scotch bonnet pepper sauce x2 ... EC$56
Delivery, paid to your driver ... EC$15
Total ........................... EC$256
≈ US$95
DELIVER TO
Keisha Browne
12 Frigate Bay Road, St Kitts
DRIVER
Kareem J. · ★ 4.9
Grey Toyota Hiace
Payment is held until you confirm delivery. Questions? Reply to this
email or visit the Help Centre (https://caribhubs.com/help).
--
CaribHubs · Basseterre, St Kitts
Notification settings: https://caribhubs.com/preferences
It comes from this template: a statement with an eyebrow, a heading, a paragraph and a button; a progress; a receipt; a meta; and a buyer family F2 footer whose note the template overrides.
Follow the layout rules
- Blocks are separated by exactly one blank line, and the part ends with a newline.
- Lines wrap at 70 characters on spaces. A word longer than that, such as a URL, sits on its own line unbroken.
- The header is the brand name (
Theme.Brand.Name) in capitals. An H2 family puts its banner in capitals on the line above; an H3 family puts its masthead in capitals on the line below. - Eyebrows, table header rows, meta labels, story eyebrows and quote cites are written in capitals.
- Bold, italic and spans contribute their text only. Code spans contribute their value.
Write actions and links
- An action (a
:button, a:link, a story or product link) is its label and a colon on one line and the full URL on the next. A trailing›on the label is dropped.01-order.out_for_delivery.txtTrack delivery: https://caribhubs.com/orders/CH-20417 - A link in prose is written
label (url), or just the URL when the label is empty or is the URL itself. An email autolink such as<ops@acme.example>is written as the bare address. - Every URL is written in full, including merge values escaped as in the HTML (D34).
Line up tables with dot leaders
Two-column tables, breakdowns, receipts and stock lists use dot leaders:
Sales · 14 orders ............... EC$1,085.00
Commission · 6% ................. −EC$65.10
Reference ....................... PO-0923-114
- Values start in one column, at the longest label plus 5, clamped to columns 34–50; a label too long for that column still gets 3 dots, so its value starts further right.
- A row is
label + " " + dots + " " + value. - A sub-value, such as the ≈ US$ total of a receipt, sits on the next line, right-aligned to the end of the value.
- A receipt line's label is
Name xQty, with nox0when the quantity is zero (D30). - A stock row is
Name · SKUagainstN leftorOut of stock. - A two-column table with a header row writes the header in capitals, padded with spaces instead of dots, so it reads as column headings (D30).
Tables with any other number of columns become padded columns, 3 spaces apart, each as wide as its widest cell. Columns the GFM table aligns right stay right-aligned:
COMMISSION NOW FROM 1 NOV
Goods 6% 6%
Services 4% 3.5%
Delivery fee EC$15 EC$15
Know each module's text form
| Module | Text |
|---|---|
statement | The eyebrow, then each heading, paragraph, list and action as its own block |
figure | The eyebrow; then the amount and its ≈ line as one block; then the copy |
letter | Each paragraph, list and action as its own block |
notice | The title and the text as one block; actions follow as their own blocks |
code | The code with its whitespace removed, then the copy |
progress | Confirmed ✓ > Packed ✓ > [On its way] > Delivered: done steps ticked, the current one in brackets |
meta | Each pair as a block: the label in capitals, then its lines, line breaks kept |
receipt, breakdown, stock, two-column table and compare | Dot leaders |
Wider table and compare | Padded columns |
stories | Each story as a block: eyebrow in capitals, title, then Read: (or its cta) and the URL |
products | Each product as a block: Name · Price, then Buy: (or its cta) and the URL |
quote | The quote, then the cite in capitals |
offer | The eyebrow, the heading and the terms as three blocks |
actions | Each action as its own block |
signature | Name, role and contact as one block |
signoff | The closing (default Thanks,) and the name (default The {brand} team) as one block |
image, map, divider | Nothing |
Lists keep their markers: - item for bullets and 1. item for numbered lists, with a hanging indent when an item wraps (D30).
Close with the footer
The footer is the lead line, a blank line, then a block starting with --:
You're getting this because you subscribed to CaribHubs updates for St
Kitts & Nevis.
--
CaribHubs · Basseterre, St Kitts
Unsubscribe: https://caribhubs.com/unsubscribe
Preferences: https://caribhubs.com/preferences
- The lead is the F1 reason, F2 note, F3 opt-out line or F3·i internal line, after any
footer.*override. - Then
--, the address line from the family'sAddresscopy, and oneLabel: URLline per entry in the family'sTextLinks. A link whose URL evaluates to empty is left out. - The F1 nav row, the F1
Linksand the F2 service line have no text form. That is why the URLs a reader needs go inTextLinks(see Families and streams).
Check the text part
The text part is checked like the HTML: a merge tag with no value, an empty action URL or an empty bound list is a render error in both parts (D31). URLs shown in both parts are checked by the HTML renderer, and text-only footer URLs are checked by Render with the same rules before either part is written (D30, D34).
The nine Quiet text parts are goldens in testdata/golden/*.txt, compared byte for byte by go test ./examples/quiet. See Goldens and testing.