Reelspan turns each post into a campaign on your self-hosted Listmonk and sends it to the list you connected. Photos are uploaded to Listmonk's media library and shown in the email above the text.
What you can post
| Post | How it appears |
|---|---|
| Text | An email campaign: a subject and the text, as HTML paragraphs |
| Photos | The same, with up to 10 photos above the text |
Videos can't be sent: the request is refused with UNSUPPORTED_POST_TYPE.
The subject is listmonk_title, else the first line of the caption (up to 200 characters), else "News". The email body is listmonk_description, else description, else the whole caption. Blank lines start new paragraphs; HTML in the text is shown as typed.
A campaign is sent to the whole list as soon as the post publishes. Send
listmonk_send=falseto save it as a draft instead, and send it from Listmonk.
The campaign is named after the subject, with "(Reelspan)" added, so you can tell it apart in Listmonk. The result's url opens the campaign in your Listmonk admin, and post_id is its id.
Connect a list
You need your Listmonk address, an API user and its token, and the list. Setup takes about two minutes.
- In Listmonk 4 or later, open Admin → Users → New, choose the API user type and copy its token.
- On an older Listmonk, use the admin username and password instead.
- In the Reelspan dashboard, open Accounts → Connect account, choose the profile and Listmonk, and enter your Listmonk address, the user, the token and the list to send to, by name or id.
Reelspan tries the pair as an API token first, then as a username and password, and checks the list exists, before saving it, encrypted.
With the API
curl -X POST https://api.reelspan.com/v1/accounts/listmonk \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"profile_username": "my-brand", "server": "news.example.com", "user": "reelspan", "token": "...", "list": "Newsletter"}'import { Reelspan } from 'reelspan';
const reelspan = new Reelspan();
await reelspan.accounts.connect('my-brand', 'listmonk', {
server: 'news.example.com',
user: 'reelspan',
token: process.env.LISTMONK_TOKEN,
list: 'Newsletter',
});import os
from reelspan import Reelspan
reelspan = Reelspan()
reelspan.accounts.connect(
"my-brand", "listmonk",
server="news.example.com", user="reelspan", token=os.environ["LISTMONK_TOKEN"], list="Newsletter",
){ "success": true, "platform": "listmonk", "account": "Newsletter", "reconnected": false }| Field | Required | Also accepted (Upload-Post) |
|---|---|---|
server |
Yes. Its address, with a path if Listmonk lives in one; a trailing /admin is removed |
instance_url |
user |
Yes. The API user, or the username | username |
token |
Yes. The API token, or the password | password |
list |
Yes. The list's name or id | list_id |
Connecting again replaces the Listmonk account on that profile. See Connect with credentials.
Example post
A newsletter with one photo:
curl -X POST https://api.reelspan.com/v1/posts/photos \
-H "Authorization: Bearer $REELSPAN_API_KEY" \
-F "user=my-brand" \
-F "platform[]=listmonk" \
-F "title=New dashboard" \
-F "listmonk_title=What's new in November" \
-F "listmonk_description=Hi there,
This month we rebuilt the dashboard around keyboard shortcuts.
Thanks for reading." \
-F "alt_text=The new dashboard" \
-F "photos[][email protected]"import { Reelspan } from 'reelspan';
import { readFile } from 'node:fs/promises';
const reelspan = new Reelspan();
const post = await reelspan.posts.photos({
user: 'my-brand',
platforms: ['listmonk'],
title: 'New dashboard',
photos: [{ data: await readFile('photo1.jpg'), name: 'photo1.jpg', type: 'image/jpeg' }],
altTexts: ['The new dashboard'],
extra: {
listmonk_title: "What's new in November",
listmonk_description: 'Hi there,\n\nThis month we rebuilt the dashboard around keyboard shortcuts.\n\nThanks for reading.',
},
});from reelspan import Reelspan
reelspan = Reelspan()
post = reelspan.posts.photos(
"my-brand", ["listmonk"], ["photo1.jpg"], "New dashboard",
alt_texts=["The new dashboard"],
extra={
"listmonk_title": "What's new in November",
"listmonk_description": "Hi there,\n\nThis month we rebuilt the dashboard around keyboard shortcuts.\n\nThanks for reading.",
},
)Fields
| Field | Meaning |
|---|---|
listmonk_title |
The email's subject. Falls back to the caption's first line. |
listmonk_description |
The email's body. Falls back to description. |
description |
The body, when listmonk_description isn't sent. |
title |
The caption: its first line is the subject and the whole of it the body, when the fields above aren't sent. |
listmonk_send |
false saves a draft campaign instead of sending it. Default: sent at once. |
listmonk_alt_text |
Alt text for the photos in the email: one text for all, or one per photo. Falls back to alt_text. |
alt_text |
The alt text for every network that takes it. |
In the dashboard composer, the Listmonk tab has Save as a draft campaign. A first_comment isn't posted on Listmonk; the result says "first_comment": "unsupported" with a warning.
Limits and behaviour
- Photos: up to 10, each up to 20 MB, uploaded to Listmonk's media library. Videos in
photos[]are left out, with a warning. - Campaigns: a regular HTML campaign to the one connected list. To send to another list, connect it on another profile.
- Drafts: a draft answers with a warning, "Saved as a draft campaign in Listmonk".
- Listmonk versions: Listmonk 4 and later with an API user; older versions with a username and password.
- https only: Reelspan always calls your Listmonk over https.
- Your server only: calls go only to the address you named, and never to private network addresses.
Common errors
| Code | When | Fix |
|---|---|---|
INVALID_CREDENTIALS |
Connecting: Listmonk accepted neither the token nor the password | Make an API user under Admin → Users (Listmonk 4+), or check the username and password. |
LIST_NOT_FOUND |
Connecting: no list by that name or id. The message lists your lists | Send one of the listed names. |
UNSUPPORTED_POST_TYPE |
The request is a video post | Send text or photos to Listmonk. |
reauth_required |
Listmonk answered 401 or 403: the token or password changed | Connect again. |
file_too_large |
A photo is over 20 MB | Send a smaller photo. |
listmonk_error |
Listmonk refused the upload or the campaign. Retried automatically on 5xx | Read error for Listmonk's reason. |
MISSING_FIELD |
Connecting without one of the four fields | Send all four. |
Errors when connecting come back as a 400 with the code in error_code. UNSUPPORTED_POST_TYPE refuses the whole request with a 400. Errors when posting are in that network's result. See Errors.