Skip to content

feat: add SecurityContext support for mTLS (mutual TLS)#273

Merged
robert-virkus merged 1 commit into
Enough-Software:mainfrom
icd360sevofficial:feat/mtls-security-context
Apr 25, 2026
Merged

feat: add SecurityContext support for mTLS (mutual TLS)#273
robert-virkus merged 1 commit into
Enough-Software:mainfrom
icd360sevofficial:feat/mtls-security-context

Conversation

@icd360sevofficial
Copy link
Copy Markdown
Contributor

Summary

Add an optional securityContext parameter to ClientBase, ImapClient, and SmtpClient to enable mutual TLS (mTLS) / client certificate authentication.

This is needed for mail servers that require client certificates for authentication (e.g., HAProxy with verify required). Currently there is no way to pass a SecurityContext to the underlying SecureSocket.connect() call.

Changes

  • ClientBase: new optional SecurityContext? securityContext field, passed to SecureSocket.connect() and SecureSocket.secure()
    • Also fixes a bug: upgradeToSslSocket() was not passing onBadCertificate to SecureSocket.secure()
  • ImapClient: forward securityContext to ClientBase super constructor
  • SmtpClient: forward securityContext to ClientBase super constructor

Usage

final context = SecurityContext()
  ..useCertificateChainBytes(utf8.encode(clientCertPem))
  ..usePrivateKeyBytes(utf8.encode(clientKeyPem));

final imapClient = ImapClient(
  isLogEnabled: true,
  onBadCertificate: (_) => true,
  securityContext: context,
);
await imapClient.connectToServer('mail.example.com', 993);

Backwards Compatibility

The parameter is optional and defaults to null. Existing code is completely unaffected — no breaking changes.

Motivation

We run a mail server with strict mTLS enforcement (HAProxy verify required). Without this change, we had to maintain a local fork of enough_mail just for these ~20 lines. This PR eliminates the need for that fork.

Add an optional `securityContext` parameter to `ClientBase`, `ImapClient`,
and `SmtpClient` to enable client certificate authentication (mTLS).

This allows passing a `SecurityContext` with client certificates and
private keys to `SecureSocket.connect()` and `SecureSocket.secure()`,
which is required for servers that enforce mutual TLS.

Changes:
- `ClientBase`: new `securityContext` field, passed to `SecureSocket.connect()`
  and `SecureSocket.secure()` (also fixes missing `onBadCertificate` in
  `upgradeToSslSocket()`)
- `ImapClient`: forward `securityContext` to `ClientBase` super constructor
- `SmtpClient`: forward `securityContext` to `ClientBase` super constructor

The parameter is optional and defaults to `null`, so this is fully
backwards-compatible with existing code.
@robert-virkus robert-virkus merged commit 0374aba into Enough-Software:main Apr 25, 2026
1 check failed
@robert-virkus
Copy link
Copy Markdown
Member

Thank you very much for your contribution and sorry for the long processing time!

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.

2 participants