I needed a way for my colleagues and clients to easily identify email problems within our mailcow infrastructure. I stumbled upon hacktisch/mailcow-status-tracker and decided to rewrite it in PHP so that it can be integrated with mailcow, the same way you would integrate roundcube.
I was already using gutmensch/docker-dmarc-report, which in turn utilizes techsneeze/dmarcts-report-parser and techsneeze/dmarcts-report-viewer, and I decided to include those as well. Actually; only the parser, I rewrote the parts of the viewer I needed.
- OAuth2 login via Mailcow (mailbox users only!)
- Configurable Admin / Domain Admin / User roles
- Uses the same mariadb instance as mailcow but a different database
- Fetches all data via API, thus you can host it on a non-mailcow server as well
- Customizable logo and footer
- Configurable retention
- Fully compatible schema with
techsneeze/dmarcts-report-parser
and derivatives, making an easy migration. - Per mailbox email open tracking (untested!!)
-
ssh to your server and go to your mailcow directory, e.g.
cd /opt/mailcow-dockerized
-
Download this project
git clone https://github.com/rallisf1/mailcow-status-app.git
- Create the database by running the following command.
source mailcow.conf
DBSTATUS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
echo Database password for user status is $DBSTATUS
docker exec -it $(docker ps -f name=mysql-mailcow -q) mysql -uroot -p${DBROOT} -e "CREATE DATABASE mailcowstatus CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
docker exec -it $(docker ps -f name=mysql-mailcow -q) mysql -uroot -p${DBROOT} -e "CREATE USER 'status'@'%' IDENTIFIED BY '${DBSTATUS}';"
docker exec -it $(docker ps -f name=mysql-mailcow -q) mysql -uroot -p${DBROOT} -e "GRANT ALL PRIVILEGES ON mailcowstatus.* TO 'status'@'%';"
Note: Store this password, you will need it later.
- Copy the contents of the web directory to
/opt/mailcow-dockerized/data/web/status
mkdir -m 755 data/web/status
cp -r mailcow-status-app/web/* data/web/status
mv data/web/status/env.example data/web/status/.env
- Copy
docker-compose.override.yml
to/opt/mailcow-dockerized
. This will allow the cron jobs to run via ofelia.
cp mailcow-status-app/docker-compose.override.yml .
Note: if you already have a docker-compose.override.yml
file, manually merge the files.
- Append
track.lua
todata/conf/rspamd/lua/rspamd.local.lua
and copytrackable.php
todata/conf/rspamd/dynmaps
UNTESTED, SKIP THIS STEP IN PRODUCTION SERVERS
cat mailcow-status-app/track.lua >> data/conf/rspamd/lua/rspamd.local.lua
cp mailcow-status-app/trackable.php data/conf/rspamd/dynmaps
Note: updating mailcow might overwrite rspamd.local.lua
. These files only affect open tracking.
-
Enable the read-only API & add the OAuth2 App in Mailcow
- Connect to your mailcow instance as an admin
- Navigate to System -> Configuration -> Access -> Administrators and Expand the API section
- In the
Allow API access from these IPs/CIDR network notations
add your mailcow server's IP addresses and the docker network ranges172.22.1.0/24
andfd4d:6169:6c63:6f77::/64
. Check yourmailcow.conf
for the rare case you've changed them. - Check
Activate API
and clickSave changes
- Copy the
API key
in a notepad to save for later - Navigate to System -> Configuration -> Access -> OAuth2 Apps and click on
+ Add OAuth2 client
- In the
Redirect URI
enterhttps://your.mailcow.com/status/callback.php
- Copy the
Client ID
andClient secret
for the next step.
-
Edit the configuration
docker-compose.override.yml
with your database password provided in step 3, and your dmarc recipient mailbox's IMAP infodata/web/status/.env
with your database password provided in step 3, your oauth2 and API credentials, your admins' emails and your customization options
-
Visit
https://your.mailcow.com/status
and login for the tables to be initialized -
Re-compose the docker containers
docker compose up -d
-
(optional) Add an App link to mailcow:
- Connect to your mailcow instance as an admin
- Navigate to System -> Configuration -> Options -> Customize
- Add a new row to
App Links
with the name you like (e.g.Status
) and the Link/status/
- Linux / BSD / Mac
- PHP 8.2+
- any web server
- MySQL / MariaDB
- Clone this project and copy the contents of the
web
directory to your web/vhost root, e.g./var/www/
- Create the
mailcowstatus
database and assign astatus
user. Save the password for later. - Install techsneeze/dmarcts-report-parser and configure it to use the database you created and the IMAP account where the DMARC reports come in
- Do steps 6 and 7 from the mailcow installation above on your mailcow server. Use the IPs of your web server in step 8.3
- Edit
.env
with your database password, your oauth2 and API credentials, your admins' emails and your customization options - Visit the web app and log in for the database tables to get created
- Set up the cron jobs: DMARC reports every 6 hours, mail logs every 5 minutes, prune daily at 2am. Adjust as you wish.
0 */6 * * * sh /path/to/the/dmarcts-report-parser.pl -i >/dev/null 2>&1
*/5 * * * * wget -O - -q http://127.0.0.1/cron/update.php?key=YOUR_CRON_KEY >/dev/null 2>&1
0 2 * * * * wget -O - -q http://127.0.0.1/cron/prune.php?key=YOUR_CRON_KEY >/dev/null 2>&1
For open tracking to work you need to add the custom attribute OPEN_TRACKING
with a value of YES
(in mailbox settings -> Custom attributes) and save
repeat for any mailboxes you wish to enable this
- A dashboard page with stats and charts
- Multi-server operation, for postfix & rspamd logs. DMARC data can already be collected from multiple (even non mailcow) servers, as this depends to the dmarc dns record on your domains.
- Notification hooks/emails for certain problems
- Change Open Tracking trigger from a custom mailbox attribute to each message's
Priority
header, thus making it a per message feature rather than a per mailbox (although personally I need to be able to control it per mailbox) - Use mailcow's theme
- Create an install.sh script, for installing in mailcow servers only.
- Use cookies for auth
Please open an issue with the feature you'd like (if one doesn't already exist). PRs are also welcome.
- Vanilla PHP with
- symfony/http-client
- vlucas/phpdotenv
- jwilsson/oauth2-client
- Flyonui for styling
- based on DaisyUI, based on tailwindCSS
Sadly, the Mailcow API returns the last X log records regardless of time and continuity. The default settings should cover 150 active mailbox users on a busy day. Adjust the POSTFIX_COUNT
, RSPAMD_COUNT
and cron frequency to mitigate for your load.
Counting rows in SQL on every query is wasting too many resources. Keep in mind this was intended to run on low power email servers that also run the whole of Mailcow.
Normally one would want to see the latest logs, or search for something specific. Since search works fine, and you get 50 results per page with back and forth buttons there's no need to add complexity. If you think otherwise feel free to fork it.
Although not advised, unless you use some other tool already, yes.
- Remove the dmarc-parser section in
docker-compose.override.yml
- Skip step 9.1
- Skip step 3
- Skip the
dmarcts-report-parser
line in step 7
Either you are using this without DMARC reporting (as described above), or its cron hasn't run yet, or it resulted in errors. The default is 6 hours, and its tables get created the first time it runs successfully.
Yes, it normally is. But we're not saving any personal information here. Both the recipient's IP and agent info are one-way hashed into a fingerprint just to let us know whenever a different client opens the same email. The nginx logs are rotated regularly enough in the mailcow instance.
To fully be GDPR compliant though we need to tell the users they are being tracked, even anonymously. That's what the TRACKER_NOTICE
environment variable does in docker-compose.override.yml
does, when set to 1.
Open tracking either fails to register multiple recipients or registers the same recipient multiple times.
This app uses a very basic fingerprinting method, which combines just the user's IP and user agent (a.k.a. web/mail client). If multiple recipients have the same IP and exactly the same client version, it will only register once for them. If the same recipient opens the same massage from multiple IPs or clients, it will register once for each combination. It's not perfect, but it's the least instrusive and easiest to implement. If you have a better idea PRs are welcome.
In a mailcow instance using helper-scripts/backup_and_restore.sh
will include this app as well. In another server you'd need the database dump and the 2 configuration files: .env
and dmarcts-report-parser.conf
, and the docker-compose.override.yml
if you customized it.
Sure, but that's up to the Mailcow developers. I'd be happy to convert the code and open a PR.
- hacktisch for hacktisch/mailcow-status-tracker's inspiration
- gutmensch for gutmensch/docker-dmarc-report, which I used until recently
- techsneeze for both the techsneeze/dmarcts-report-parser and techsneeze/dmarcts-report-viewer
- mailcow for their incredible mail server solution