We host several thousands e-commerce entities at Shoptet.cz. Each on its own domain. A good half of them is using freemail as their main e-mail address, some are using our mailboxes and some use their own. We have to transmit emails generated by their customers and order processing for all of them and we offer basic newsletter solution too (along with advanced integration with MailChimp).
As anyone else we have been forced by Seznam.cz to introduce DKIM for mass emails. We have learned that Seznam.cz is going to build sender’s reputation on the combination of DKIM selector and domain – this means we must use different combination for every e-commerce entity. And we do not want to allow users to change this combination – if they behave like spammers, they should not have bad influence on other our users.
We use postfix and naturally we started with opendkim. The documentation is not the strongest part of the project, so after many hours we came with this setup:
SigningTable.lua was tough, giving us endless Segmentation fault until we discovered, we cannot return nil.
The global variable query passed to SigningTable contains content of the “From” header. This does not allow us to distinguish e-commerce entities. People could use their freemail address. Until recently there existed directive
SenderHeaders Sender,From where different headers could have been used, but this had gone in opendkim 2.10.0 release. We have decided to put it back, but not that versatile – we just hardcoded support for header called:
X-DKIM-Sender. Because of internal guts it must have @ in the content, so we pass information about our entity as
selector=domain@dkim. You can see in the script below, that we will strip @dkim, and separate selector and domain using the = sign.
You can see we sign everything coming from this mail server with the same private key. Our public key is a TXT record on dkim.shoptet.cz. In order to create a unique selector for every entity we created wildcard CNAME:
*._domainkey.news.shoptet.cz CNAME dkim.shoptet.cz. The final step is to modify the sending applications to include the
X-DKIM-Sender header. If the user has verified their domain, we would pass this:
If they did not we will use this:
We have combined this with Postfix Sender Rewriting Scheme daemon (to deliver all bouncing messages and auto-replies to the real sender) and hardened SPF record for news.shoptet.cz.
SpamAssassin now shows in the first case DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU. In the later DKIM_VALID_AU is missing obviously.
This article was written to help others seeking help with opendkim, perhaps they will not have to read so much C code as I had to to figure this all out 😉
Customer usage of SMTP
Out customers send their email from their email clients using our SMTP server. In this case we have to use email address from their MAIL FROM SMTP command, otherwise they would be able to forge From: header. This requires changes in opendkim:
Finally on this SMTP server we must use special