The default `{{ TrackLink "https://listmonk.app" }}` template function
is clumsy to write and does breaks WYSIWYG editors and HTML syntax
highlighting because of the quotes. The new syntax doesn't break HTML
and is easier to write.
Eg: `<a href="https://listmonk.app@TrackLink">Link</a>`
- Introduce @TrackLink shorthand.
- Add first-class support for tracking links in the WYSIWYG (TinyMCE)
editor by introducing an on/off checkbox on the link dialog.
- Improve default dummy campaign content to highlight this.
- Add indexes.
- Refactor dashboard charts and view/click count queries.
(~10x speed bump on a setup of 7mn subscribers and 80mn views)
- Refactor get subscriber queries.
(~10x speed bump on 7mn subscribers)
- Make subscriber UI issue an equality query for email seach strings.
- Blocklist or unsubscribe subscribers based on a bounce threshold
- Add /bounces UI for viewing bounces and in the subscriber view
- Add settings UI for managing bounce settings
- Add support for scanning POP3 bounce mailboxes
- Add a generic webhook for posting custom bounces at /webhooks/bounce
- Add SES bounce webhook support at /webhooks/services/ses
- Add Sendgrid bounce webhook support at /webhooks/services/sendgrid
Previously, converting between formats simply copied over raw content.
This update does actual conversion between different formats. While
lossy, this seems to a good enough approximation for even reasonbly
rich HTML content. Closes#348.
- richtext, html => plain
Strips HTML and converts content to plain text.
- richtext, html => markdown
Uses turndown (JS) lib to convert HTML to Markdown.
- plain => richtext, html
Converts line breaks in plain text to HTML breaks.
- richtext => html
"Beautifies" the HTML generated by the WYSIWYG editor unlike the
earlier behaviour of dumping one long line of HTML.
- markdown => richtext, html
Makes an API call to the backend to use the Goldmark lib to convert
Markdown to HTML.
This commit removes the Go html2text lib that would automatically
convert all HTML messages to plaintext and add them as the alt
text body to outgoing e-mails. This lib also had memory leak
issues with certain kinds of HTML templates.
A new UI field for optionally adding an alt plaintext body to
a campaign is added. On enabling, it converts the HTML message in
the campaign editor into plaintext (using the textversionjs lib).
This introduces breaking changes in the campaigns table schema,
model, and template compilation.
This is a major feature that builds upon the `Messenger` interface
that has been in listmonk since its inception (with SMTP as the only
messenger). This commit introduces a new Messenger implementation, an
HTTP "postback", that can post campaign messages as a standard JSON
payload to arbitrary HTTP servers. These servers can in turn push them
to FCM, SMS, or any or any such upstream, enabling listmonk to be a
generic campaign messenger for any type of communication, not just
e-mails.
Postback HTTP endpoints can be defined in settings and they can be
selected on campaigns.
- antd+react was resulting in extremely clunky and unreadable
spaghetti frontend code (primarily due to how antd is).
- Buefy is lighter by an order of magnitude, has excellent
responsive views (especially tables) and usability.
- Vue's templating produces far more readable template code.
- Campaigns now have a `type` property (regular, opt-in)
- Opt-in campaigns work for double opt-in lists and e-mail
subscribers who haven't confirmed their subscriptions.
- Lists UI shows a 'Send opt-in campaign' optin that
automatically creates an opt-in campaign for the list
with a default message body that can be tweaked before
sending the campaign.
- Primary usecase is to send opt-in campaigns to subscribers
who are added via bulk import.
This is a breaking change. Adds a new Postgres enum type
`campaign_type` and a new column `type` to the campaigns table.
- Lists can now be marked as single | double optin.
- Insert subscribers to double opt-in lists send out a
confirmation e-mail to the subscriber with a confirmation link.
- Add `{{ OptinURL }}` to template functions.
This is a breaking change. Adds a new field 'optin' to the lists
table and changes how campaigns behave. Campaigns on double opt-in
lists exclude subscribers who haven't explicitly confirmed subscriptions.
Changes the structure and behaviour of how notification e-mail routines,
including notif email template compilation, notification callbacks for
campaign and bulk import completions.
- Better template function shorthand substitution.
- Make `UnsubscribeURL` a function consitent with TrackLink.
This is a breaking change that makes the old `.UnsubscrbeURL`
obsolete.
This commit introduces a `blobstore` package and refactors the existing
upload mechanism. Upload is now handled by `providers` and the two
bundled providers are `S3` and `Filesystem`. `app.Blobstore` initialises
the correct provider based on the configuration and handles `Put`,
`Delete` and `Get` operations.
- Simplify campaigns querying to separate statistics gather into
a separate query for lazy loading.
- Simplify subscribers query to separate list fetching into
a separate query for lazy loading.
Quill link dialog (righly) escapes quotes in URL values there by breaking the
TrackLink() template function. That is, {{ TrackLink "https://listmonk.app" }}
when inserted using the Quill link dialog would become
{{ TrackLink "https://listmonk.app" }}. A simplework around is to
add support to backticks so that the template parser works with
{{ TrackLink `https://listmonk.app` }}
- Add a name / e-mail "quicksearch" input to the UI
- Implement row selection and aggregation at table level and a "select all" that selects all rows at the query level
- On selected subscribers, add bulk list management (add / remove / unsubscribe), blacklist, and delete
- Add notifications for campaign state change
- Add notifications for import state change
Related changes.
- Add a new 'templates' directory with HTML templates
- Move the static campaign template as a .tpl file into it
- Change Messenger.Push() to accept multiple recipients
- Change exhaustCampaign()'s behaviour to pass metadata to admin emails