Send Email in Tiptap
Send transactional emails using Tiptap JSON format (same as Lumail editor)
/api/v1/emailsThe TIPTAP content type uses the same JSON format as the Lumail email editor. This is ideal for programmatically generating complex email layouts with rich components like buttons, images, columns, and more.
Quick Example
curl -X POST https://lumail.io/api/v1/emails \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "[email protected]",
"subject": "Welcome!",
"contentType": "TIPTAP",
"content": "{\"type\":\"doc\",\"content\":[{\"type\":\"heading\",\"attrs\":{\"level\":1},\"content\":[{\"type\":\"text\",\"text\":\"Hello \"}]},{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"Welcome to our platform!\"}]}]}",
"from": "[email protected]"
}'import { Lumail } from "lumail";
const lumail = new Lumail({ apiKey: "YOUR_API_TOKEN" });
await lumail.emails.send({
to: "[email protected]",
subject: "Welcome!",
contentType: "TIPTAP",
content: JSON.stringify({
type: "doc",
content: [
{
type: "heading",
attrs: { level: 1 },
content: [{ type: "text", text: "Hello " }],
},
{
type: "paragraph",
content: [{ type: "text", text: "Welcome to our platform!" }],
},
],
}),
from: "[email protected]",
});JSON Structure
Tiptap uses a tree-based JSON structure:
{
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "Hello world!"
}
]
}
]
}Supported Node Types
Text Nodes
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "Regular text"
}
]
}Headings
{
"type": "heading",
"attrs": { "level": 1 },
"content": [{ "type": "text", "text": "Heading 1" }]
}Variables
Insert subscriber data with the variable node:
{
"type": "variable",
"attrs": {
"id": "name",
"fallback": "Friend"
}
}Buttons
{
"type": "button",
"attrs": {
"text": "Click Here",
"url": "https://example.com",
"variant": "filled",
"buttonColor": "#007bff",
"textColor": "#ffffff"
}
}Images
{
"type": "image",
"attrs": {
"src": "https://example.com/image.png",
"alt": "Description",
"width": 600,
"alignment": "center"
}
}Survey
One-question poll. Recipients click an answer in the inbox. Same node as the campaign editor — see Surveys for settings, filters and the workflow trigger.
{
"type": "survey",
"attrs": {
"surveyId": "svy_abcdefghij",
"question": "What should we write about next?",
"style": "buttons",
"allowComment": false,
"alignment": "left",
"buttonColor": "#000000",
"textColor": "#ffffff",
"options": [
{ "id": "opt_a1b2c3d4e5", "label": "Talk about AI", "emoji": "🤖" },
{ "id": "opt_f6g7h8i9j0", "label": "No AI please", "emoji": "🙅" }
]
}
}| Attr | Required | Values |
|---|---|---|
surveyId | yes | svy_ + 10 alphanumeric characters, unique in the document |
question | yes | 1–300 characters, no merge fields |
style | no | buttons (default), yes_no, nps, emoji |
options | yes* | 2–8 { id, label, emoji? }. Ignored for nps (fixed nps_0…nps_10) |
allowComment | no | true / false (default). Comment max 1000 characters |
npsLowLabel / npsHighLabel | no | Author captions, max 60. null translates on the vote page |
alignment | no | left (default), center, right |
buttonColor / textColor | no | Hex. Defaults black / white |
surveyId is the join key for every recorded answer. Do not reuse one across
campaigns. Copying a campaign regenerates it. Surveys cannot live inside a
repeat block.
Spacer
{
"type": "spacer",
"attrs": {
"height": 20
}
}Horizontal Rule
{
"type": "horizontalRule"
}Columns (Two-Column Layout)
{
"type": "columns",
"attrs": {
"borderColor": "",
"borderRadius": "0",
"borderWidth": "0"
},
"content": [
{
"type": "column",
"attrs": { "width": 50 },
"content": [
{
"type": "paragraph",
"content": [{ "type": "text", "text": "Left column" }]
}
]
},
{
"type": "column",
"attrs": { "width": 50 },
"content": [
{
"type": "paragraph",
"content": [{ "type": "text", "text": "Right column" }]
}
]
}
]
}Text Formatting (Marks)
Apply formatting with marks:
{
"type": "text",
"text": "Bold and italic",
"marks": [{ "type": "bold" }, { "type": "italic" }]
}Available Marks
| Mark | Description |
|---|---|
bold | Bold text |
italic | Italic text |
underline | Underlined text |
strike | Strikethrough |
link | Hyperlink |
Link Mark
{
"type": "text",
"text": "Visit our website",
"marks": [
{
"type": "link",
"attrs": {
"href": "https://example.com",
"target": "_blank"
}
}
]
}Complete Example
{
"to": "[email protected]",
"subject": "Welcome to our platform!",
"contentType": "TIPTAP",
"content": {
"type": "doc",
"content": [
{
"type": "heading",
"attrs": { "level": 1, "textAlign": "center" },
"content": [
{ "type": "text", "text": "Welcome, " },
{
"type": "variable",
"attrs": { "id": "name", "fallback": "Friend" }
},
{ "type": "text", "text": "!" }
]
},
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "Thanks for signing up. We're excited to have you on board."
}
]
},
{
"type": "spacer",
"attrs": { "height": 20 }
},
{
"type": "button",
"attrs": {
"text": "Get Started",
"url": "https://example.com/dashboard",
"variant": "filled",
"buttonColor": "#007bff",
"textColor": "#ffffff",
"alignment": "center"
}
},
{
"type": "spacer",
"attrs": { "height": 30 }
},
{
"type": "horizontalRule"
},
{
"type": "footer",
"attrs": { "textAlign": "center" },
"content": [
{
"type": "text",
"text": "You received this email because you signed up on our website."
}
]
}
]
},
"from": "[email protected]",
"preview": "Welcome to our platform"
}Exporting from Lumail Editor
You can get the Tiptap JSON from the Lumail email editor:
- Create your email in the Lumail editor
- Open browser developer tools (F12)
- In the console, access the editor's
getJSON()method - Copy the JSON structure for API use
Automatic Features
When using Tiptap format, Lumail automatically:
- Adds unsubscribe footer if no
{{unsubscribeUrl}}is present - Replaces variables with subscriber data
- Tracks opens via invisible pixel
- Tracks clicks by wrapping links
- Generates plain text version
Best Practices
- Use the Lumail editor to prototype your email structure
- Test with variables to ensure fallbacks work correctly
- Keep layouts simple for better email client compatibility
- Use buttons for important calls-to-action
- Include alt text for all images