Skip to content

[Feature] Add Mailpit module#1727

Open
0xced wants to merge 2 commits into
testcontainers:developfrom
0xced:feature/add-mailpit
Open

[Feature] Add Mailpit module#1727
0xced wants to merge 2 commits into
testcontainers:developfrom
0xced:feature/add-mailpit

Conversation

@0xced

@0xced 0xced commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

This pull request resurrects #1134 to work with the current Testcontainers API.

Attribution to @feslima is preserved in cc70a2f. Then some refinements have been applied in commit 2405430.

Tests have also been added to cover all possible configurations.

  1. No SMTP authentication
  2. Insecure SMTP authentication (no TLS)
  3. Secure SMTP authentication (self-signed TLS certificate)

Why is it important?

See #1134.

Also, having mail in the module name is much better than Papercut when you are looking for an email related container. 😁

Related issues

Summary by CodeRabbit

  • New Features
    • Added Mailpit support, including a container builder and configuration options for SMTP auth, insecure mode, and max message retention.
    • Exposed mapped SMTP port and a helper to retrieve the Mailpit web/API base address.
  • Documentation
    • Added Mailpit to the modules documentation with links to Docker image, package, and source.
  • Tests
    • Introduced end-to-end tests validating email delivery via Mailpit’s HTTP API for default, secure-auth, and insecure-auth scenarios.
    • Pinned the Mailpit test image to a specific digest for consistent runs.

@0xced
0xced requested review from a team and HofmeisterAn as code owners July 16, 2026 10:12
@netlify

netlify Bot commented Jul 16, 2026

Copy link
Copy Markdown

Deploy Preview for testcontainers-dotnet ready!

Name Link
🔨 Latest commit 2405430
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-dotnet/deploys/6a5a2869ebb601000794edde
😎 Deploy Preview https://deploy-preview-1727--testcontainers-dotnet.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds a Mailpit container module with configurable SMTP authentication, message retention, mapped endpoints, integration tests, solution registration, centralized package versioning, and module documentation.

Changes

Mailpit container module

Layer / File(s) Summary
Mailpit configuration and project contracts
src/Testcontainers.Mailpit/MailpitConfiguration.cs, src/Testcontainers.Mailpit/MailpitBuilder.cs, src/Testcontainers.Mailpit/Testcontainers.Mailpit.csproj, src/Testcontainers.Mailpit/Usings.cs, src/Testcontainers.Mailpit/.editorconfig
Defines immutable Mailpit configuration, builder construction and cloning, project dependencies, and project configuration.
Mailpit builder and container runtime
src/Testcontainers.Mailpit/MailpitBuilder.cs, src/Testcontainers.Mailpit/MailpitContainer.cs
Adds SMTP authentication and message-retention settings, port bindings, readiness checks, configuration merging, and mapped endpoint accessors.
Mailpit SMTP and API integration tests
tests/Testcontainers.Mailpit.Tests/*, Directory.Packages.props
Adds SMTP/API message verification with default, secure-authentication, and insecure-authentication fixtures, plus MailKitLite version management and pinned test image configuration.
Solution and module registration
Testcontainers.slnx, docs/modules/index.md
Registers the production and test projects and documents the Mailpit module.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Test
  participant MailpitFixture
  participant MailpitSMTP
  participant MailpitAPI
  Test->>MailpitFixture: Send MimeMessage
  MailpitFixture->>MailpitSMTP: Submit message over SMTP
  MailpitSMTP-->>MailpitFixture: Return message ID
  MailpitFixture->>MailpitAPI: Request message by ID
  MailpitAPI-->>MailpitFixture: Return message JSON
  MailpitFixture-->>Test: Return parsed message
Loading

Possibly related PRs

Suggested labels: enhancement, module

Suggested reviewers: hofmeisteran

Poem

I’m a rabbit with mail in my paws,
SMTP hops without pauses.
Through Mailpit’s bright API door,
Messages return with fields galore.
Secure or not, the tests all cheer—
“Your little inbox works right here!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR delivers the requested mail-testing module with SMTP API verification and optional TLS/auth support.
Out of Scope Changes check ✅ Passed The changes stay focused on the new Mailpit module, tests, docs, and project wiring without clear unrelated additions.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding a new Mailpit module.
Description check ✅ Passed The description covers what changed, why it matters, and related issues, which matches the required template well.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@0xced 0xced changed the title Feature/add mailpit [Feature] Add Mailpit module Jul 16, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
tests/Testcontainers.Mailpit.Tests/MailpitContainerTest.cs (1)

46-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a substring check for the certificate issuer to prevent cross-platform test flakiness.

The ordering of Relative Distinguished Names (RDNs) in the Issuer string can vary depending on the underlying cryptographic library used by the OS (e.g., OpenSSL on Linux might format it as O=..., CN=... instead of CN=..., O=...). Consider using .Contains() instead of an exact match to ensure the test passes reliably across all platforms.

♻️ Proposed refactor
             using var smtpClient = new SmtpClient();
-            smtpClient.ServerCertificateValidationCallback = (_, certificate, _, _) => certificate?.Issuer == "CN=localhost, O=Mailpit self-signed certificate";
+            smtpClient.ServerCertificateValidationCallback = (_, certificate, _, _) => certificate?.Issuer.Contains("Mailpit self-signed certificate") == true;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Testcontainers.Mailpit.Tests/MailpitContainerTest.cs` around lines 46 -
47, Update the ServerCertificateValidationCallback in MailpitContainerTest to
validate the certificate issuer using a substring check for the expected Mailpit
self-signed certificate identity, rather than requiring an exact RDN ordering.
Preserve the existing null-certificate rejection behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/Testcontainers.Mailpit/.editorconfig`:
- Line 1: Remove the root = true setting from the module-level .editorconfig so
it inherits the repository-level formatting configuration. Keep any other
module-specific editor settings unchanged.

In `@src/Testcontainers.Mailpit/MailpitBuilder.cs`:
- Around line 82-89: Update WithSmtpAuthCredentials in MailpitBuilder so each
call removes or clears the previously configured mutually exclusive SMTP
environment variables before applying the settings for the current allowInsecure
value. Ensure the resulting builder state contains either
MP_SMTP_AUTH_ALLOW_INSECURE or the TLS certificate/key variables, never both,
when calls use different values.
- Around line 71-76: Update WithSmtpAuthCredentials to validate credentials is
non-null before accessing credentials.UserName, throwing the appropriate
argument-null exception for a null parameter while preserving the existing colon
validation for non-null credentials.

In `@src/Testcontainers.Mailpit/MailpitConfiguration.cs`:
- Around line 13-18: Update src/Testcontainers.Mailpit/MailpitConfiguration.cs
lines 13-18 so the smtpAuthAllowInsecure and maxMessages parameters use nullable
bool? and uint? types with null defaults, preserving explicit false and 0 values
during BuildConfiguration.Combine. Update lines 63-77 so the
SmtpAuthAllowInsecure and MaxMessages properties use matching nullable types.

---

Nitpick comments:
In `@tests/Testcontainers.Mailpit.Tests/MailpitContainerTest.cs`:
- Around line 46-47: Update the ServerCertificateValidationCallback in
MailpitContainerTest to validate the certificate issuer using a substring check
for the expected Mailpit self-signed certificate identity, rather than requiring
an exact RDN ordering. Preserve the existing null-certificate rejection
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 87037c8f-c9d0-4468-ad82-3a105cd86ee5

📥 Commits

Reviewing files that changed from the base of the PR and between 2fa209a and 8a591aa.

📒 Files selected for processing (16)
  • Directory.Packages.props
  • Testcontainers.sln
  • Testcontainers.slnx
  • docs/modules/index.md
  • src/Testcontainers.Mailpit/.editorconfig
  • src/Testcontainers.Mailpit/MailpitBuilder.cs
  • src/Testcontainers.Mailpit/MailpitConfiguration.cs
  • src/Testcontainers.Mailpit/MailpitContainer.cs
  • src/Testcontainers.Mailpit/Testcontainers.Mailpit.csproj
  • src/Testcontainers.Mailpit/Usings.cs
  • tests/Testcontainers.Mailpit.Tests/.editorconfig
  • tests/Testcontainers.Mailpit.Tests/.runs-on
  • tests/Testcontainers.Mailpit.Tests/Dockerfile
  • tests/Testcontainers.Mailpit.Tests/MailpitContainerTest.cs
  • tests/Testcontainers.Mailpit.Tests/Testcontainers.Mailpit.Tests.csproj
  • tests/Testcontainers.Mailpit.Tests/Usings.cs

Comment thread src/Testcontainers.Mailpit/.editorconfig
Comment thread src/Testcontainers.Mailpit/MailpitBuilder.cs
Comment on lines +82 to +89
return allowInsecure
? builder
.WithEnvironment("MP_SMTP_AUTH_ALLOW_INSECURE", "1")
: builder
// https://mailpit.axllent.org/docs/configuration/certificates/#auto-generate-self-signed-certificates
.WithEnvironment("MP_SMTP_TLS_CERT", "sans:localhost")
.WithEnvironment("MP_SMTP_TLS_KEY", "sans:localhost");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Handle mutually exclusive environment variables on subsequent calls.

If WithSmtpAuthCredentials is called multiple times on the same builder instance with different values for allowInsecure, the environment variables from the previous calls will leak into the new builder state because .WithEnvironment adds or overwrites keys, but does not remove existing ones.

This could result in both MP_SMTP_AUTH_ALLOW_INSECURE and TLS certificates being configured simultaneously. You should explicitly clear the mutually exclusive keys (or defer environment variable resolution to the Build phase using the properties stored in MailpitConfiguration).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Testcontainers.Mailpit/MailpitBuilder.cs` around lines 82 - 89, Update
WithSmtpAuthCredentials in MailpitBuilder so each call removes or clears the
previously configured mutually exclusive SMTP environment variables before
applying the settings for the current allowInsecure value. Ensure the resulting
builder state contains either MP_SMTP_AUTH_ALLOW_INSECURE or the TLS
certificate/key variables, never both, when calls use different values.

Comment on lines +13 to +18
public MailpitConfiguration(NetworkCredential smtpAuthCredentials = null, bool smtpAuthAllowInsecure = true, uint maxMessages = 100)
{
SmtpAuthCredentials = smtpAuthCredentials;
SmtpAuthAllowInsecure = smtpAuthAllowInsecure;
MaxMessages = maxMessages;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use nullable types for configuration properties.

In Testcontainers, configuration properties are merged using BuildConfiguration.Combine(old, new). Since Combine checks against default(T), non-nullable types fail to merge correctly when explicitly set to their default values (e.g., false for bool, 0 for uint). This means users won't be able to explicitly disable auto-deletion (by setting it to 0) or enforce STARTTLS (by setting it to false), as those values will be treated as unset and overwritten by defaults.

  • src/Testcontainers.Mailpit/MailpitConfiguration.cs#L13-L18: Change the smtpAuthAllowInsecure and maxMessages constructor parameters to bool? and uint? (with null as the default value) so explicit assignments are preserved.
  • src/Testcontainers.Mailpit/MailpitConfiguration.cs#L63-L77: Change the SmtpAuthAllowInsecure and MaxMessages properties to bool? and uint? to support the updated constructor.
📍 Affects 1 file
  • src/Testcontainers.Mailpit/MailpitConfiguration.cs#L13-L18 (this comment)
  • src/Testcontainers.Mailpit/MailpitConfiguration.cs#L63-L77
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Testcontainers.Mailpit/MailpitConfiguration.cs` around lines 13 - 18,
Update src/Testcontainers.Mailpit/MailpitConfiguration.cs lines 13-18 so the
smtpAuthAllowInsecure and maxMessages parameters use nullable bool? and uint?
types with null defaults, preserving explicit false and 0 values during
BuildConfiguration.Combine. Update lines 63-77 so the SmtpAuthAllowInsecure and
MaxMessages properties use matching nullable types.

@0xced
0xced force-pushed the feature/add-mailpit branch from 8a591aa to c46dbb7 Compare July 16, 2026 14:16

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/Testcontainers.Mailpit.Tests/MailpitContainerTest.cs (1)

54-58: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Cleanly disconnect the SMTP client.

MailKit's SmtpClient does not send a QUIT command upon Dispose(). It is recommended to explicitly disconnect before disposal to ensure a clean termination of the connection with the server.

♻️ Proposed refactor
             var result = await smtpClient.SendAsync(message, cancellationToken);
+            await smtpClient.DisconnectAsync(true, cancellationToken);
 
             var messageId = QueuedMessage().Match(result).Groups[1].Value;
             Assert.NotEmpty(messageId);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Testcontainers.Mailpit.Tests/MailpitContainerTest.cs` around lines 54 -
58, Update the SMTP client cleanup in the test flow containing SendAsync and
QueuedMessage to explicitly disconnect the MailKit SmtpClient before disposal,
ensuring the disconnect occurs after sending completes and regardless of success
or failure.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/Testcontainers.Mailpit.Tests/MailpitContainerTest.cs`:
- Around line 54-58: Update the SMTP client cleanup in the test flow containing
SendAsync and QueuedMessage to explicitly disconnect the MailKit SmtpClient
before disposal, ensuring the disconnect occurs after sending completes and
regardless of success or failure.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f6d5db1f-8924-4d50-be9a-5009162ba9a4

📥 Commits

Reviewing files that changed from the base of the PR and between 8a591aa and c46dbb7.

📒 Files selected for processing (15)
  • Directory.Packages.props
  • Testcontainers.slnx
  • docs/modules/index.md
  • src/Testcontainers.Mailpit/.editorconfig
  • src/Testcontainers.Mailpit/MailpitBuilder.cs
  • src/Testcontainers.Mailpit/MailpitConfiguration.cs
  • src/Testcontainers.Mailpit/MailpitContainer.cs
  • src/Testcontainers.Mailpit/Testcontainers.Mailpit.csproj
  • src/Testcontainers.Mailpit/Usings.cs
  • tests/Testcontainers.Mailpit.Tests/.editorconfig
  • tests/Testcontainers.Mailpit.Tests/.runs-on
  • tests/Testcontainers.Mailpit.Tests/Dockerfile
  • tests/Testcontainers.Mailpit.Tests/MailpitContainerTest.cs
  • tests/Testcontainers.Mailpit.Tests/Testcontainers.Mailpit.Tests.csproj
  • tests/Testcontainers.Mailpit.Tests/Usings.cs
🚧 Files skipped from review as they are similar to previous changes (11)
  • tests/Testcontainers.Mailpit.Tests/.editorconfig
  • src/Testcontainers.Mailpit/Usings.cs
  • src/Testcontainers.Mailpit/.editorconfig
  • tests/Testcontainers.Mailpit.Tests/Usings.cs
  • Testcontainers.slnx
  • src/Testcontainers.Mailpit/MailpitContainer.cs
  • src/Testcontainers.Mailpit/Testcontainers.Mailpit.csproj
  • tests/Testcontainers.Mailpit.Tests/Testcontainers.Mailpit.Tests.csproj
  • src/Testcontainers.Mailpit/MailpitConfiguration.cs
  • docs/modules/index.md
  • src/Testcontainers.Mailpit/MailpitBuilder.cs

@0xced
0xced force-pushed the feature/add-mailpit branch from c46dbb7 to 75e1e0e Compare July 17, 2026 07:14
Also make sure that Mailpit can be used without authentication if not configured and improve SMTP authentication configuration by letting the user choose whether to use a self-signed certificate or to allow insecure PLAIN and LOGIN SMTP authentication.
@0xced
0xced force-pushed the feature/add-mailpit branch from 75e1e0e to 2405430 Compare July 17, 2026 13:04
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.

[Feature]: Module for MailHog container for integration testing SMTP clients

2 participants