Sendy has some massive problems with code quality and always had. The last time I took a look at it (because I needed to send emails), it was quite horrendous. I would not be surprised if it was insecure - was literally a "nooooooope" right back out.
Background: I write PHP for fun, I don't compete with Sendy, I don't have any stake in any service that competes with Sendy. I also don't expect PHP to be written in the most OOP-everything Symfony-esque way either. But this is a bit too much for me even.
It doesn't follow any modern standards or guidelines; it doesn't use any templating system, just PHP hardcoded inline with HTML in hundreds of files (no modern framework, lightweight or not), concatenated variables into SQL queries and HTML. The author seems to hate using { } for if/else statements, which has the potential of introducing fun bugs if not extremely careful. 1 and 2 letter variable names are common (and I don't mean in the way of $i or $j); parts of it border on insane or bizarre; there are 500 character lines where instead of an error generation feature they just die() with a full HTML document as a string for error pages; functions are written inline all over the place and they all use the keyword global; there are no parameterised queries - it's covered in repetitive mysqli_real_escape_string and query concatenation. There is a massive amount of copy-pasted code: instead of some kind of single database management layer, there's a re-definition of a function that connects to a database with the same name in dozens of files, all of which try to read global variables (doesn't take any parameters)
A client of mine uses it (believe me moving their mailing list into their main app is absolutely scheduled work) and thus I’ve had the “pleasure” getting to know it in an apparently non-common scenario for sendy users.
Our MySQL env is a pxc/galera cluster, and connections require tls. When I asked the developer about adding tls support (about 4 lines of code if you’re using mysqli as he is) I just got a flat “nope, not doing that”.
At which point I lost all reservations about deobfuscating the “protected” files and simply replacing the db setup call in every single god damn file with a single setup that accepts tls options.
I’ve worked on some garbage code projects, but sendy is almost deliberately bad. In one place it: disabled all error reporting; tries to connect to the database; fails silently if the connection doesn’t succeed.
There is zero logging (besides an ungodly number of notices and warnings about undeclared variables, etc) and the author has apparently zero interest in actually fixing or improving any part of it at a technical level.
For those who work in php and want a comparison: it makes Wordpress in general look like a well architected application.
I'm curious, what made you go with a multiple lists approach instead of tagging users on a single list?
A lot of popular (but expensive) services like ConvertKit have moved to a tagging approach many many years ago.
It's so much easier to manage your list of emails when it's a single list and then you add tags to specific users like "purchased X". This way the email address only exists in 1 spot and you can segment on the tags.
The Sendy approach (and from the looks of it your app too) becomes very unwieldy with having to manage, parse and merge multiple lists on a regular basis.
+1 for this approach. This was the #1 design decision we made with BigMailer.io back in 2015. It's not trivial to change the model once you go with unique lists approach.
Performance is extra helpful for making real-time segment size calculations. We use elastic search and it's costly.
listmonk supports arbitrary nested tags and attributes in the form of JSON. A subscriber can have properties like {"purchased_x": true, ...}. It's possible to issue complex SQL expressions to filter and send campaigns to subscribers.
The multi-list approach has several other benefits. When manager / sender (and other) permissions get introduced, it will be straight forward to restrict users to managing certain lists. In addition, multiple lists allow subscribers to selectively subscribe / unsubscribe from lists.
Internally, the structure is simple. There is only one subscribers table and subscriber data is not duplicated anywhere. List (foreign key) relationships are in a separate table.
So in theory could you have 1 list and each subscriber has many tags, and then you can segment on those tags?
Also, do you have any public success stories beyond your own Zerodha campaigns? Have you compared delivery / bounce / etc. rates vs Sendy and other tools using the same email providers? Also how fast can you send emails out through SES?
Okay. Again, different target group. Sendy targets people who have no idea what msmtp is. They upload the files to their web host, enter a database password the hoster have them and AWS credentials, and they are done.
Background: I write PHP for fun, I don't compete with Sendy, I don't have any stake in any service that competes with Sendy. I also don't expect PHP to be written in the most OOP-everything Symfony-esque way either. But this is a bit too much for me even.
It doesn't follow any modern standards or guidelines; it doesn't use any templating system, just PHP hardcoded inline with HTML in hundreds of files (no modern framework, lightweight or not), concatenated variables into SQL queries and HTML. The author seems to hate using { } for if/else statements, which has the potential of introducing fun bugs if not extremely careful. 1 and 2 letter variable names are common (and I don't mean in the way of $i or $j); parts of it border on insane or bizarre; there are 500 character lines where instead of an error generation feature they just die() with a full HTML document as a string for error pages; functions are written inline all over the place and they all use the keyword global; there are no parameterised queries - it's covered in repetitive mysqli_real_escape_string and query concatenation. There is a massive amount of copy-pasted code: instead of some kind of single database management layer, there's a re-definition of a function that connects to a database with the same name in dozens of files, all of which try to read global variables (doesn't take any parameters)