Skip to content

Storing DKIM information in the database#308

Open
MrSleeps wants to merge 1 commit into
vexim:masterfrom
MrSleeps:dkim
Open

Storing DKIM information in the database#308
MrSleeps wants to merge 1 commit into
vexim:masterfrom
MrSleeps:dkim

Conversation

@MrSleeps

@MrSleeps MrSleeps commented Jun 11, 2026

Copy link
Copy Markdown

DKIM keys stored in the vexim database, been running this for years (been a couple of sql updates over the years). Forgot to update the issue I posted almost 10 years ago about it.

Left dkim_sign_headers up to Exims standard signing because despite many hours of testing, could never get a stable dkim result with it.. Exims built in has worked fine for it (it's a busy mailserver).

The SQL is basic but leaves in the option to add sign_headers if you so want.

Cf #97

@rimas-kudelis rimas-kudelis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to stuff below:

  1. since this doesn't come with any UI, maybe it should wait until we get rid of the default admin panel?
  2. The table structure doesn't seem to protect against having duplicate records for the same domain, or having none. What happens in these cases?

Comment on lines +45 to +47
DKIM_CANON = relaxed
DKIM_STRICT = 0
DKIM_TIMESTAMPS = 0

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these hardcoded, especially DKIM_CANON which has its own column in the database?

Also, I don't like how you didn't define DKIM_SIGN_HEADERS on purpose, but kept the database column. IMO, a commented out macro with an explanation about why it's been commented out would fit here better.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, here's my DKIM_SIGN_HEADERS:

DKIM_SIGN_HEADERS = +Content-Type:+MIME-Version:+Date:+Message-ID:+To:+Subject:+From:+Sender:=Reply-To:+Cc:+Content-ID:+Content-Description:=Resent-Date:=Resent-From:=Resent-Sender:=Resent-To:=Resent-Cc:=Resent-Message-ID:+In-Reply-To:+References:=List-Id:=List-Help:=List-Unsubscribe:=List-Subscribe:=List-Post:=List-Owner:=List-Archive

I think it's been working nicely for me for quite a while now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to not use the default which conforms to RFC?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really remember what problem I was solving by editing these values myself. It's probably what I said here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainly it's as it is to start a discussion on what is needed/wanted.

We hard code them at work because we have a lot of email accounts and reducing sql look ups is never a bad thing (you can set the canon via sql if you really wanted, hence it's there).

Same with DKIM sign headers, those are left to Exims defaults but if people want to change them per domain they can?

You have to remember there was no activity on this repo, I had no idea what direction you wanted to go with it.

The table structure doesn't seem to protect against having duplicate records for the same domain, or having none. What happens in these cases?

Why would it? How do you rotate secrets if you just delete the old one? Any mail in transit that hasn't caught up with the new key in the dns would fail?

As for having no key, it would fail. That's a personal preference, in todays world of email not having a dkim key and trying to send email is kind of pointless.

You could do something like

DKIM_SELECTOR = ${lookup mysql {SELECT d.selector FROM dkim d JOIN domains dom ON d.domain_id = dom.domain_id WHERE dom.domain = '${quote_mysql:DKIM_DOMAIN}' AND d.enabled = 1}{$value}{}}
DKIM_PRIVATE_KEY = ${lookup mysql {SELECT d.private_key FROM dkim d JOIN domains dom ON d.domain_id = dom.domain_id WHERE dom.domain = '${quote_mysql:DKIM_DOMAIN}' AND d.enabled = 1}{$value}{}}

And have in the transports have something that looks something like:

dkim_selector = ${if def:DKIM_SELECTOR {DKIM_SELECTOR}{}}
dkim_private_key = ${if def:DKIM_PRIVATE_KEY {DKIM_PRIVATE_KEY}{}}

Which wouldn't sign the email if it didn't have a key (in theory, currently untested)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you rotate the public keys on your DNS servers? Automaded/Manual?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fully automated (thousands of domains would take days!), every 3 months a new one gets generated, dns runs off a sql backend (pdns) so it's dead simple. Generate key, update the dns sql and add the new key to email database. A week later the old key gets deleted. The old key is kept so dns propagation isn't an issue.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to mention, the keys get a new selector when they are rotated so it would be jan2026 for one and the new one would be jun2026 for example.

DKIM_TIMESTAMPS = 0

# Disable DKIM verification for incoming mail (since we don't want to verify inbound)
DKIM_VERIFY_DOMAIN = ${if match_domain{$sender_address_domain}{+local_domains}{0}{1}}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a new macro? I don't see it being used on Bookworm.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't actually mean to leave that in there..

Was working on an acl that uses it

acl_smtp_dkim:
  # Only verify external senders
  condition = ${if eq {DKIM_VERIFY_DOMAIN}{1}}
  
  # If verification fails, set a variable
  warn
    dkim_status = fail
    set acl_m_dkim_fail = yes
    log_message = DKIM failure from $sender_address_domain: $dkim_verify_reason

  # Accept otherwise
  accept

But exim does (at least on trixie) have this on the check_rcpt acl

.ifdef DISABLE_DKIM_VERIFY

So it seemed kinda pointless

Comment thread docs/dkim/dkim.sql

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we ship with this functionality, then this file should go to docs/setup/migrations, and if not, maybe all of this could just go to the Wiki?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in 2026 it needs some kind of dkim in the core vexim setup, DKIM has been around since the mid 00s.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants