KLYRN
KLYRN Web
All documentation
  1. Home
  2. Docs
  3. Mail

Mail

A server that does not host mail can still send it. Configure one relay, and mail(), WordPress, Laravel and anything else that calls sendmail works on every site.

What this is, and what it is not

A KLYRN server can host mail: mailboxes, forwarders, catch-all, DKIM, Rspamd spam filtering into Junk, and webmail at /webmail on every site. A site's mail() then goes through that local mail server and is DKIM-signed on the way out.

On a server that does not host mail, every site can send through one relay you own. This page is about the relay. With neither, a contact form that calls mail() has nothing to hand its message to.

Outbound
Through a relay you own: your Google Workspace, Amazon SES, Postmark, or any SMTP server with a username and a password.
Per site
Each site sends as its own domain, is rate limited on its own, and keeps its own log.

Turning it on

You need a relay to send through, and the switch. Both are in the panel under Settings. The relay is configured once for the server. Presets for eleven providers fill in the host, port and encryption:

Gmail / Google Workspace
smtp.gmail.com, 587 STARTTLS, or 465 TLS
Microsoft 365 / Outlook
smtp.office365.com, 587 STARTTLS
Amazon SES
email-smtp.<region>.amazonaws.com, 587 STARTTLS, or 465 TLS
SendGrid
smtp.sendgrid.net, 587 STARTTLS, or 465 TLS
Mailgun
smtp.mailgun.org, 587 STARTTLS, or 465 TLS
Postmark
smtp.postmarkapp.com, 587 or 2525 STARTTLS
Brevo
smtp-relay.brevo.com, 587 STARTTLS, or 465 TLS
Zoho Mail
smtp.zoho.com, 587 STARTTLS, or 465 TLS
Fastmail
smtp.fastmail.com, 465 TLS, or 587 STARTTLS
Mailjet
in-v3.mailjet.com, 587 STARTTLS, or 465 TLS
SMTP2GO
mail.smtp2go.com, 587 STARTTLS, or 465 TLS
Other relay
Any host, any port, 587 STARTTLS by default

Switching it on installs Postfix, writes the configuration, and points every site's PHP pool at KLYRN's own wrapper. It is idempotent. Running it twice on a correct server changes nothing, writes nothing and reloads nothing.

What switching it on costs. Changing a site's PHP pool restarts its PHP-FPM master, as any pool change does. That is one sub-second restart per account. Two hundred sites across forty accounts cost forty restarts. A second run costs none: main PIDs and reload counts were measured identical on every master.

What a site sends as

A site on shop.example sends as site@shop.example. The local part is one server-wide setting and defaults to site. The domain always comes from the site itself, and the domain decides whether SPF passes.

The default is site because a contact form's reply goes to this address, and nobody reads noreply.

Each PHP pool gets a sendmail_path that points at KLYRN. That is what gives each site its own identity, rate limit and log:

php_admin_value[sendmail_path] = klyrn sendmail --site shop.example \
    --from site@shop.example --limit 100 --logdir /var/log/klyrn/mail -t -i

A site whose mail is not configured has no sendmail_path line at all and behaves as it did before. No state exists where some messages leave and some do not.

Rate limits and message size

Default rate
100 messages per site per hour
Maximum message
10 MiB including attachments
Scope
Per site, so one busy shop cannot spend another site's budget

A contact form sends single figures an hour, and a busy shop's order confirmations send tens. At this limit a compromised site can emit 2,400 messages a day. That is enough to be noticed and too few to get your server's address blocklisted first.

The rate is a server-wide setting and can be raised or lowered. Setting it to zero stops that server sending without uninstalling anything.

SPF, DKIM and DMARC

Receivers decide whether to believe your mail from three records. KLYRN checks them for each sending domain and reports what it found:

SPF
Checked: that exactly one record exists, and that it authorises your relay. Two SPF records is a failure, and a common one.
DKIM
Checked, never generated. With a relay, the relay signs, so DKIM is set up at your provider.
DMARC
Checked, and KLYRN reports what the record asks receivers to do with a failure.

Mail that is accepted by your relay has not been delivered. KLYRN says so. Until something has been delivered, check SPF, DKIM and DMARC for each sending domain before trusting the path. A relay refusing its own customer's mail is usually refusing the From domain.

The queue, and what is stuck

The panel shows the outbound queue broken down by what each message is waiting on, with the oldest arrival time and the total size on disk:

Active
Being delivered right now
Incoming
Accepted from a site and waiting to be picked up
Deferred
Tried, failed, will be retried. Grouped by the reason, because a hundred messages deferred for one reason is one problem
Hold
Held deliberately and will not move until released

A queue record KLYRN cannot parse is still counted in the total and left out of the breakdown.

Why nothing can reach this from outside

The Postfix KLYRN installs is a null client. KLYRN writes the configuration, and the reasons are in the file:

inet_interfaces = loopback-only   # no listener on any public interface
mydestination =                   # nothing is delivered on this machine
mynetworks = 127.0.0.0/8 [::1]/128  # only this machine may submit
relayhost = [smtp.example.net]:587  # required; never direct-to-MX
No public listener
inet_interfaces = loopback-only. With no listener to reach, there is no open relay to find.
No local delivery
mydestination is empty, so no address on this machine is a destination.
No direct-to-MX
A relay is required. Mail sent straight to recipients from a hosting IP lands in spam.
Not a tenant's to change
/etc/postfix belongs to KLYRN. A site cannot rewrite its own sender or raise its own limit.

The relay password is stored sealed and is never returned by the API. The panel is told whether a password is set, never what it is. It is redacted from support bundles in every export shape KLYRN produces.

Lists, filters and delivery

A mailing list can live on any mail domain hosted here. It has members, a rule for who may post (members, anyone or moderators), a subject prefix and an optional reply to the list.

Leaving takes one step with a confirmation. Each post carries List-Id and List-Unsubscribe headers and is DKIM-signed as the list.

Each mailbox can have its own filters. Spam settings apply per domain and per mailbox. Track delivery shows whether mail to or from your domains was delivered, deferred or bounced.

Turning it off

Disabling removes the sendmail_path from every pool and stops Postfix. KLYRN owns the files it wrote:

/etc/postfix/main.cf
/etc/postfix/master.cf
/etc/postfix/sasl_passwd
/etc/postfix/sender_canonical

After disabling, mail() returns false again, as it does on a server that never had this switched on.

Discord WhatsApp