Signing Messages
Automatic signing (Venmail MTA)
Section titled “Automatic signing (Venmail MTA)”When VVS-1 signing is enabled on your Venmail server, all outgoing messages are signed automatically. The MTA:
- Looks up the agent key for the sending domain
- Canonicalizes the body and headers
- Signs with Ed25519
- Adds VVS headers before DKIM signing (so DKIM covers them too)
No code changes needed — just enable signing in your server config and register your agent key.
Client-side signing
Section titled “Client-side signing”For higher security, you can sign messages yourself before sending via the API. This means Venmail never holds your private key.
import { vvs } from '@venmail/vsm';
// Generate a keypair (do this once, store securely)const keyPair = vvs.generateKeyPair();console.log('Public key:', keyPair.publicKeyBase64url);// Publish this at /.well-known/venmail-agent/billing
// Sign a messageconst result = vvs.signMessage( '<p>Please process invoice #8821</p>', { subject: 'Invoice #8821', date: new Date().toUTCString(), }, { privateKey: keyPair.privateKey, verifyMethods: ['well-known', 'dns'], keyVersion: 1, });
// result.headers contains all X-Venmail-* headers// Pass them as custom headers when sendingawait fetch('https://m.venmail.io/api/v1/send/message', { method: 'POST', headers: { 'X-Server-API-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json', }, body: JSON.stringify({ subject: 'Invoice #8821', html_body: '<p>Please process invoice #8821</p>', headers: result.headers, }),});use Venmail\VVS\KeyGenerator;use Venmail\VVS\Signer;
// Generate keypair (once, store securely)$keyPair = KeyGenerator::generate();// Publish $keyPair->publicKeyBase64url at well-known endpoint
// Sign a message$result = Signer::signMessage( '<p>Please process invoice #8821</p>', [ 'subject' => 'Invoice #8821', 'date' => gmdate('D, d M Y H:i:s +0000'), ], new \Venmail\VVS\SigningOptions( privateKey: $keyPair->privateKey, verifyMethods: ['well-known', 'dns'], keyVersion: 1, ));
// Pass $result->headers as custom headers when sendingCanonical signing payload
Section titled “Canonical signing payload”The payload signed is constructed as:
{agent_id}\n{timestamp}\n{nonce}\n{content_hash}\n{canonicalized_headers}\nWhere canonicalized_headers is built from the from, to, subject, and date headers — lowercased, trimmed, sorted alphabetically, joined with newlines.
See the Header Reference for the complete canonicalization algorithm.