From fb302bf8e85d7874b690564596a90a702b26bdfe Mon Sep 17 00:00:00 2001 From: wgroeneveld Date: Wed, 29 Dec 2021 14:53:40 +0100 Subject: [PATCH] listmonk --- .../migrating-from-mailchimp-to-listmonk.md | 65 ++++++++++++++++++ static/post/2021/12/listmonk.png | Bin 0 -> 20165 bytes 2 files changed, 65 insertions(+) create mode 100644 content/post/2021/12/migrating-from-mailchimp-to-listmonk.md create mode 100644 static/post/2021/12/listmonk.png diff --git a/content/post/2021/12/migrating-from-mailchimp-to-listmonk.md b/content/post/2021/12/migrating-from-mailchimp-to-listmonk.md new file mode 100644 index 00000000..ddc2e687 --- /dev/null +++ b/content/post/2021/12/migrating-from-mailchimp-to-listmonk.md @@ -0,0 +1,65 @@ +--- +title: Migrating from Mailchimp to Listmonk +date: 2021-12-29T14:19:00+01:00 +categories: + - software +tags: + - privacy + - go +--- + +In January of 2022, Mailchimp's [General Data Protection Regulation](https://mailchimp.com/intuit-completes-mailchimp-acquisition/) (GDPR) is about to change. Why? Intuit acquired Mailchimp, requiring a slew of legal-related changes, such as terms of use, data processing options, etc. I don't do mailing lists myself, but my wife uses Mailchimp for her small start-up to send out monthly "moments of revelation" or _lichtpuntjes_ (Dutch people: [take a look and subscribe!](https://kristienthoelen.be/lichtpuntjes/)). + +Trained as a lawyer, she of course is very mindful of data regulation issues. Mailchimp's off-site---outside of the European Union---server location was always a bit of a pickle, and now with the acquisition, things got worse. According to her, they're not complaint with the latest GDPR rules and still hiding behind the [now dead EU-US Privacy Shield](https://www.gdprauditing.com/eu-us-privacy-shield-is-dead/). Long story short: we wanted to take control of her data: the subscribers. + +An excessively long list of Mailchimp alternatives didn't make the choice any easier. Elimination of outside-of-Europe server locations did shorten it by quite a bit, but one of the other problems with Mailchimp-alike solutions is its needless **complexity**. My wife and me regularly got lost in the menu navigation and sheer volume of options, while all we wanted to do is compose a mail and send it out. + +My growing interest in the [Go](/tags/go) programming language made me stumble upon [Listmonk.app](https://listmonk.app/) a few months ago. This was the perfect time to try it out. It's essentially a _simple_ and self-contained self-hosted solution that uses a Postgres DB to store the sensitive data, meaning we can decide where to physically put it. The installation was dead-easy: `./listmonk --new-config` and `./listmonk --install`. Yay, we've got an instance up and running! + +The only downside (and perhaps also upside) of simpler alternatives is the focused usability: Listmonk is nothing but a shell that manages your subscriptions and email campaigns. The actual _sending_ of the mails, through SMTP or whatnot, is _not_ done through the application, but requires the configuration of an external mail server. After failed attempts to try and get it to work with `smtp.gmail.com`, I was ready to de-install it. Until I thought "what am I doing?"---[email is not secure](https://latacora.micro.blog/2020/02/19/stop-using-encrypted.html), the headers are never encrypted, I'm still giving Google all contact information. Why would I do that? + +The alternatives are MailGun, Coresender (which even has a [nice Listmonk + Coresender install page](https://coresender.com/integrations/listmonk)), and the like, that are very expensive if your mailing list only contains 30 subscribers. Since I had a Postfix install up and running anyway, why not try to configure SMTP server `localhost`? First tests are cautiously optimistic. I am just waiting to hit the DMARC-failure-wall, but so far, we've tried sending it to a few different servers, without activating any spam filter. Great! + +In case my future self is looking to reproduce the success, here are the steps I took to install and configure everything: + +1. Download, extract, and configure listmonk. +2. [Create a listmonk Postgres user, database, grant rights](https://orahow.com/create-user-in-postgresql/). (`CREATE USER listmonk WITH PASSWORD 'jaddajadda';`) +3. Create a listmonk Linux account. Add `hostname:port:database:username:password` to `600`-chmodded `.pgpass` for backups. +4. Set SMTP server at `localhost:25`. Pray you've got things in order at the Postfix side. +5. Configure lists and whatnot in Listmonk. +6. Add a `pg_dump` command to `crontab` to timely auto-backup. +7. Add a `listmonk.service` in `/etc/systemd/system`. +8. Update all ansible scripts to automatically execute all previous steps! + +My wife's site is a Wordpress install, meaning it uses PHP. I created a small server-side security check to avoid spammers from subscribing, and to anti-corrupt the Mailchimp interface. Thanks to that layer, it was easy to plug out and replace with a new one for Listmonk. It uses `curl` to call the [API /Subscribers](https://listmonk.app/docs/apis/subscribers/) to subscribe new members to the respective mailing lists. Something like this: + +```php +// $tag is the human-readable mailing list name +public function subscribe($email, $tag) { + if(!$this->validateMail($email)) { + return $this->error('email'); + } + if(!$this->validateTag($tag)) { + return $this->error('tag'); + } + + $url = self::$server . "/api/subscribers"; + $payload = '{ "preconfirm_subscriptions": true, "name": "anonymous", "email": "' . $email . '", "status": "enabled", "lists": [' . self::$tags[$tag] . '] }'; + $json = $this->curl($url, "POST", $payload); + + return $this->success(); +} +``` + +Listmonk uses numbered IDs in the `lists` array, which kind of sucks, so associative array `$tags` "solves" this. Lastly, since we don't want to collect a name, but the API still requires one, I simply submit "anonymous". + +![](../listmonk.png "The Listmonk Campaign page.") + +So far, we're happy with the switch. A few things to take into account: + +- There's no Dutch translation available---yet. I'll try to do the translation in the coming days. +- In Mailchimp, you could send a "welcome!" mail after each subscription. I can hack my way around this but haven't found the feature here. +- The content template uses Go's templating engine. While I love this, it's a bit difficult for my wife to use, and there's no box to pick template keys from. + +Hopefully the next campaign that launches will successfully land in every mailbox! At least now we fully control everything and can simplify our own privacy statement. + diff --git a/static/post/2021/12/listmonk.png b/static/post/2021/12/listmonk.png new file mode 100644 index 0000000000000000000000000000000000000000..5e97d9551291b193a92418dd09b340e8ae7ba1f8 GIT binary patch literal 20165 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 XsgI7~i{VfF=qEalvOyLayWam75*UM$ literal 0 HcmV?d00001