Billionmail/BillionMail · error
Cannot read DKIM public key: %v
Error message
Cannot read DKIM public key: %v
What it means
Thrown when the DKIM public key file (dkimPubPath inside/on the rspamd container) cannot be read. The library needs the key's base64 body to assemble the DNS TXT record, so failure here aborts DKIM record generation.
Source
Thrown at core/internal/service/domains/domains.go:645
if err != nil {
err = fmt.Errorf("Failed to write DKIM sign config: %v", err)
return
}
// Restart rspamd service
err = dk.RestartContainerByName(context.Background(), consts.SERVICES.Rspamd)
if err != nil {
err = fmt.Errorf("Failed to restart rspamd container: %v", err)
return
}
}
}
// DKIM public key is typically stored in a specific location in the container or host
// Assuming we use docker exec to read the DKIM public key from the rspamd container
dkimPub, err := public.ReadFile(dkimPubPath)
if err != nil {
err = fmt.Errorf("Cannot read DKIM public key: %v", err)
return
}
// Format DKIM record
// Expected format is a pre-formatted TXT record value like "v=DKIM1; k=rsa; p=MIIBIjANBg..."
dkimRecord := strings.TrimSpace(dkimPub)
// If the raw public key is read, format it into DNS TXT record format
if !strings.Contains(dkimRecord, "v=DKIM1") && !strings.Contains(dkimRecord, "k=rsa") && !strings.Contains(dkimRecord, "p=") {
// Remove possible header/footer markers and newlines
dkimRecord = strings.ReplaceAll(dkimRecord, "-----BEGIN PUBLIC KEY-----", "")
dkimRecord = strings.ReplaceAll(dkimRecord, "-----END PUBLIC KEY-----", "")
dkimRecord = strings.ReplaceAll(dkimRecord, "\n", "")
dkimRecord = strings.TrimSpace(dkimRecord)
dkimRecord = fmt.Sprintf("v=DKIM1; k=rsa; p=%s", dkimRecord)
} else {
var ms [][]string
ms, err = gregex.MatchAllString(`"([^"\r\n]+)"`, dkimRecord)View on GitHub (pinned to fc36c76c05)
Solutions
- Confirm the DKIM key file exists at dkimPubPath (ls) and regenerate it via RepairDKIMSigningConfig if missing
- Fix read permissions/ownership on the key file
- Verify the rspamd data volume is mounted so the key path resolves on the host
- Check the rspamd version/config for a changed dkim key path and update dkimPubPath accordingly
Example fix
// before: read fails silently for caller
if _, err := os.Stat(dkimPubPath); os.IsNotExist(err) {
// regenerate keys first via RepairDKIMSigningConfig
}
dkimPub, err := public.ReadFile(dkimPubPath) Defensive patterns
Strategy: validation
Validate before calling
if fi, err := os.Stat(dkimPubPath); err != nil || fi.IsDir() || fi.Size() == 0 {
return fmt.Errorf("DKIM public key missing or empty at %s — run RepairDKIMSigningConfig", dkimPubPath)
} Type guard
func dkimKeyExists(path string) bool {
fi, err := os.Stat(path)
return err == nil && fi.Mode().IsRegular() && fi.Size() > 0
} Try / catch
dkimPub, err := public.ReadFile(dkimPubPath)
if err != nil {
log.Printf("DKIM public key unreadable at %s: %v — regenerate via RepairDKIMSigningConfig", dkimPubPath, err)
return err
} Prevention
- Generate DKIM keys as part of domain onboarding before exposing DNS record endpoints
- Verify the rspamd data volume mapping matches dkimPubPath after image upgrades
- Alert on empty or zero-length key files
When it happens
Trigger: public.ReadFile(dkimPubPath) errors — the DKIM key file was never generated, path changed between rspamd versions, permissions deny read, or the file lives inside the container while the code reads a host path (or vice versa).
Common situations: Fresh domain where the keypair generation step was skipped or failed earlier, rspamd image update moving the key location, volume not mounted so the key file is absent on the host, wrong permissions after manual key regeneration.
Related errors
- Failed to write DKIM public key: %v
- Failed to read DKIM sign config: %v
- Failed to write DKIM sign config: %v
- failed to write DKIM signing config: %v
- Failed to generate DKIM key pair: %v
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/bf70a0c1a0d14c9b.
Report an issue: GitHub.