[GH-ISSUE #539] Docker container: add snakeoil cert/key #346

Closed
opened 2026-03-15 14:00:41 +03:00 by kerem · 19 comments
Owner

Originally created by @WilliamDEdwards on GitHub (Jul 17, 2025).
Original GitHub issue: https://github.com/axllent/mailpit/issues/539

I use Mailpit to test mail sending.

In my script, STARTTLS is enabled when configured. When testing locally, I start the Mailpit container, bind-mounting my key material:

services:
  mailpit:
    image: axllent/mailpit:v1.27
    ports:
      - "8212:8025"
      - "8138:1025"
    environment:
      MP_SMTP_TLS_CERT: /etc/ssl/certs/mailpit_cert.pem
      MP_SMTP_TLS_KEY: /etc/ssl/private/mailpit_key.pem
    volumes:
      - type: bind
        source: ./mailpit_cert.pem
        target: /etc/ssl/certs/mailpit_cert.pem
      - type: bind
        source: ./mailpit_key.pem
        target: /etc/ssl/private/mailpit_key.pem

However, this doesn't work in GitLab CI: when starting Mailpit as a service, the container has no access to my repository. Therefore, I can't provide Mailpit with the key material it requires to enable STARTTLS.

Proposed solution: add a default snakeoil cert/key to the Docker container, allowing for STARTTLS to be enabled in any situation.

Originally created by @WilliamDEdwards on GitHub (Jul 17, 2025). Original GitHub issue: https://github.com/axllent/mailpit/issues/539 I use Mailpit to test mail sending. In my script, STARTTLS is enabled when configured. When testing locally, I start the Mailpit container, bind-mounting my key material: ``` services: mailpit: image: axllent/mailpit:v1.27 ports: - "8212:8025" - "8138:1025" environment: MP_SMTP_TLS_CERT: /etc/ssl/certs/mailpit_cert.pem MP_SMTP_TLS_KEY: /etc/ssl/private/mailpit_key.pem volumes: - type: bind source: ./mailpit_cert.pem target: /etc/ssl/certs/mailpit_cert.pem - type: bind source: ./mailpit_key.pem target: /etc/ssl/private/mailpit_key.pem ``` However, this doesn't work in GitLab CI: when starting Mailpit as a service, the container has no access to my repository. Therefore, I can't provide Mailpit with the key material it requires to enable STARTTLS. Proposed solution: add a default snakeoil cert/key to the Docker container, allowing for STARTTLS to be enabled in any situation.
kerem 2026-03-15 14:00:41 +03:00
Author
Owner

@axllent commented on GitHub (Jul 18, 2025):

Hi @WilliamDEdwards. I guess I could add a default snakeoil certificate to the Docker images.

  1. This certificate would obviously be different each time a Docker image is generated - would this be an issue?
  2. Would this certificate require any specific Common Name? I assume not if one is not validating the certificate, but I thought it best to check with you to get your thoughts.
<!-- gh-comment-id:3086974248 --> @axllent commented on GitHub (Jul 18, 2025): Hi @WilliamDEdwards. I guess I could add a default snakeoil certificate to the Docker images. 1. This certificate would obviously be different each time a Docker image is generated - would this be an issue? 2. Would this certificate require any specific Common Name? I assume not if one is not validating the certificate, but I thought it best to check with you to get your thoughts.
Author
Owner

@WilliamDEdwards commented on GitHub (Jul 18, 2025):

Hi @axllent,

  1. Generating a new certificate when starting the container is fine. For this use case, the only thing that matters is that STARTTLS can be enabled - not that the generated certificate is consistent or valid.
  2. For this use case, CN/SANs don’t matter. Again, all is well as long as STARTTLS can be enabled :)

Needless to say auto-generated certificates would be unsuitable for production. Probably good to add that to the docs.

Finally, if the user specifies a certificate themselves (using env vars or args), we could skip certificate generation altogether.

<!-- gh-comment-id:3087642226 --> @WilliamDEdwards commented on GitHub (Jul 18, 2025): Hi @axllent, 1. Generating a new certificate when starting the container is fine. For this use case, the only thing that matters is that STARTTLS can be enabled - not that the generated certificate is consistent or valid. 2. For this use case, CN/SANs don’t matter. Again, all is well as long as STARTTLS can be enabled :) Needless to say auto-generated certificates would be unsuitable for production. Probably good to add that to the docs. Finally, if the user specifies a certificate themselves (using env vars or args), we could skip certificate generation altogether.
Author
Owner

@axllent commented on GitHub (Jul 18, 2025):

Thanks for the prompt reply. I'm actually thinking of bundling the certificate with the docker image, much easier that doing it conditionally on the fly (permissions etc).

<!-- gh-comment-id:3088324203 --> @axllent commented on GitHub (Jul 18, 2025): Thanks for the prompt reply. I'm actually thinking of bundling the certificate with the docker image, much easier that doing it conditionally on the fly (permissions etc).
Author
Owner

@WilliamDEdwards commented on GitHub (Jul 18, 2025):

Bundling a default certificate would be fine I suppose, but I’m not sure what the convention is in container-land(?)

I suppose some image security scanners (often used by enterprises) could complain about a private key being included(?)

Thank you for the prompt reply too :)

<!-- gh-comment-id:3088604732 --> @WilliamDEdwards commented on GitHub (Jul 18, 2025): Bundling a default certificate would be fine I suppose, but I’m not sure what the convention is in container-land(?) I suppose some image security scanners (often used by enterprises) could complain about a private key being included(?) Thank you for the prompt reply too :)
Author
Owner

@axllent commented on GitHub (Jul 18, 2025):

That's a good point about the certs, although from my testing this did not trigger any alarms in the container.

Anyway, while I experiment, can you please confirm something for me - does this certificate work for your intended purpose? certs.zip

<!-- gh-comment-id:3089332370 --> @axllent commented on GitHub (Jul 18, 2025): That's a good point about the certs, although from my testing this did not trigger any alarms in the container. Anyway, while I experiment, can you please confirm something for me - does this certificate work for your intended purpose? [certs.zip](https://github.com/user-attachments/files/21316434/certs.zip)
Author
Owner

@axllent commented on GitHub (Jul 19, 2025):

Full disclosure: I'm working on a system where Mailpit is capable to generating temporary self-signed certificates on-the-fly. This should be easy to integrate in your testing, however I need to know if that certificate example I provided will work in your infrastructure.

<!-- gh-comment-id:3091433272 --> @axllent commented on GitHub (Jul 19, 2025): Full disclosure: I'm working on a system where Mailpit is capable to generating temporary self-signed certificates on-the-fly. This should be easy to integrate in your testing, however I need to know if that certificate example I provided will work in your infrastructure.
Author
Owner

@WilliamDEdwards commented on GitHub (Jul 20, 2025):

That key material works.

<!-- gh-comment-id:3094424734 --> @WilliamDEdwards commented on GitHub (Jul 20, 2025): That key material works.
Author
Owner

@axllent commented on GitHub (Jul 21, 2025):

If I can please pick your brains? My approach is that Mailpit will be capable of generating self-signed certs on-the-fly. It will use the existing flag/environment options, however unlike --smtp-tls-cert /path/to/cert.pem, you would do something like --smtp-tls-cert self:localhost,mailpit,mailpit.local which would allow you to specify one or more comma-separated names for which the self-signed certificate are generated. I think most clients won't care if you're already skipping validation checks, however some SMTP clients require the SAN (Subject Alt Name) to also match the hostname, even with self-signed certs.

My question is, what "prefix" do you think is most suitable for the above? I have suggested self: above, but it could technically be anything (eg: tls://<domain>). I'm going around in circles and don't know who else to ask :)

<!-- gh-comment-id:3095166519 --> @axllent commented on GitHub (Jul 21, 2025): If I can please pick your brains? My approach is that Mailpit will be capable of generating self-signed certs on-the-fly. It will use the existing flag/environment options, however unlike `--smtp-tls-cert /path/to/cert.pem`, you would do something like `--smtp-tls-cert self:localhost,mailpit,mailpit.local` which would allow you to specify one or more comma-separated names for which the self-signed certificate are generated. I think most clients won't care if you're already skipping validation checks, however some SMTP clients require the SAN (Subject Alt Name) to also match the hostname, even with self-signed certs. My question is, what "prefix" do you think is most suitable for the above? I have suggested `self:` above, but it could technically be anything (eg: `tls://<domain>`). I'm going around in circles and don't know who else to ask :)
Author
Owner

@WilliamDEdwards commented on GitHub (Jul 21, 2025):

Hi @axllent,

If I can please pick your brains?

I have only one brain, so I'll take that as a compliment :P

My approach is that Mailpit will be capable of generating self-signed certs on-the-fly. It will use the existing flag/environment options, however unlike --smtp-tls-cert /path/to/cert.pem, you would do something like --smtp-tls-cert self:localhost,mailpit,mailpit.local which would allow you to specify one or more comma-separated names for which the self-signed certificate are generated. I think most clients won't care if you're already skipping validation checks, however some SMTP clients require the SAN (Subject Alt Name) to also match the hostname, even with self-signed certs.

My question is, what "prefix" do you think is most suitable for the above? I have suggested self: above, but it could technically be anything (eg: tls://). I'm going around in circles and don't know who else to ask :)

I doubt making --smtp-tls-cert a union is intuitive. Reasons:

  • You'd have to validate that --smtp-tls-key is unset, when --smtp-tls-cert is set but is not a file (or just let --smtp-tls-key be a NOP then, but that's unintuitive)
  • Users might think that self: has a special meaning, which would then have to be explained, i.e. it's ambiguous
  • Users might think that other prefixes are possible too, which is not the case IIUC

I think it would be most intuitive to add a new, mutually exclusive argument with the following signature:

--smtp-tls-autogenerate san,san,...

Main advantage: it's immediately clear to users what this argument does (autogenerate), without introducing an ambiguous term such as 'self'.

--smtp-tls-autogenerate would be mutually exclusive with --smtp-tls-cert and --smtp-tls-key.

What do you think?

<!-- gh-comment-id:3096321884 --> @WilliamDEdwards commented on GitHub (Jul 21, 2025): Hi @axllent, > If I can please pick your brains? I have only one brain, so I'll take that as a compliment :P > My approach is that Mailpit will be capable of generating self-signed certs on-the-fly. It will use the existing flag/environment options, however unlike --smtp-tls-cert /path/to/cert.pem, you would do something like --smtp-tls-cert self:localhost,mailpit,mailpit.local which would allow you to specify one or more comma-separated names for which the self-signed certificate are generated. I think most clients won't care if you're already skipping validation checks, however some SMTP clients require the SAN (Subject Alt Name) to also match the hostname, even with self-signed certs. > > My question is, what "prefix" do you think is most suitable for the above? I have suggested self: above, but it could technically be anything (eg: tls://<domain>). I'm going around in circles and don't know who else to ask :) I doubt making `--smtp-tls-cert` a union is intuitive. Reasons: - You'd have to validate that `--smtp-tls-key` is unset, when `--smtp-tls-cert` is set but is not a file (or just let `--smtp-tls-key` be a NOP then, but that's unintuitive) - Users might think that `self:` has a special meaning, which would then have to be explained, i.e. it's ambiguous - Users might think that other prefixes are possible too, which is not the case IIUC I think it would be most intuitive to add a new, mutually exclusive argument with the following signature: --smtp-tls-autogenerate san,san,... Main advantage: it's immediately clear to users what this argument does (autogenerate), without introducing an ambiguous term such as 'self'. `--smtp-tls-autogenerate` would be mutually exclusive with `--smtp-tls-cert` and `--smtp-tls-key`. What do you think?
Author
Owner

@axllent commented on GitHub (Jul 21, 2025):

Thanks. I hear what you're saying, but I was actually intending not to add new flags because I would need to introduce 3 new flags and environment variables (SMTP, UI/API and POP3), hence to reuse what's already there. Mailpit already has quite a large list of flags, so I do my best to keep this number down where possible.

<!-- gh-comment-id:3098067624 --> @axllent commented on GitHub (Jul 21, 2025): Thanks. I hear what you're saying, but I was actually intending not to add new flags because I would need to introduce 3 new flags and environment variables (SMTP, UI/API and POP3), hence to reuse what's already there. Mailpit already has quite a large list of flags, so I do my best to keep this number down where possible.
Author
Owner

@WilliamDEdwards commented on GitHub (Jul 21, 2025):

I understand your reasoning, but from my perspective as an end user, clarity and unambiguous wording outweighs the amount of flags. A large among of flags could be intimidating, but “if you confuse, you lose.”

That said, if you’re (understandably) not adding a flag, I would say that sans: as a prefix is most intuitive.

<!-- gh-comment-id:3098564720 --> @WilliamDEdwards commented on GitHub (Jul 21, 2025): I understand your reasoning, but from my perspective as an end user, clarity and unambiguous wording outweighs the amount of flags. A large among of flags could be intimidating, but “if you confuse, you lose.” That said, if you’re (understandably) not adding a flag, I would say that `sans:` as a prefix is most intuitive.
Author
Owner

@axllent commented on GitHub (Jul 21, 2025):

Thank you - You make a valid point. I'll give this some more thought and will weigh one up against the other 👍

<!-- gh-comment-id:3099512458 --> @axllent commented on GitHub (Jul 21, 2025): Thank you - You make a valid point. I'll give this some more thought and will weigh one up against the other 👍
Author
Owner

@WilliamDEdwards commented on GitHub (Jul 22, 2025):

Thanks for your work on this in any case!

<!-- gh-comment-id:3103112424 --> @WilliamDEdwards commented on GitHub (Jul 22, 2025): Thanks for your work on this in any case!
Author
Owner

@axllent commented on GitHub (Jul 24, 2025):

I've decided to go with the sans:<san1>[,<san2>....] syntax, else I know this (3 new flags, 3 new environment variables) will haunt/bug me for a long time :) I appreciate your input though, however I think this is somewhat a niche use.

This has now been merged into develop, meaning it's available in the axllent/mailpit:edge build. I haven't updated any documentation yet (will only do that once this gets released).

Would you please be able to test the edge build for me to confirm it works as you would expect?

The certificate syntax (flag or env) is the same as it was before, except you now use sans:localhost for both to use a self-generated certificate. If the sans for both differ (ie: different hostnames) then Mailpit will abort as the private and public keys won't match, so there is a little bit of repetitiveness (I know.... tradeoff of my approach). Thanks.

<!-- gh-comment-id:3112034095 --> @axllent commented on GitHub (Jul 24, 2025): I've decided to go with the `sans:<san1>[,<san2>....]` syntax, else I know this (3 new flags, 3 new environment variables) will haunt/bug me for a long time :) I appreciate your input though, however I think this is somewhat a niche use. This has now been merged into develop, meaning it's available in the `axllent/mailpit:edge` build. I haven't updated any documentation yet (will only do that once this gets released). Would you please be able to test the edge build for me to confirm it works as you would expect? The certificate syntax (flag or env) is the same as it was before, except you now use `sans:localhost` for both to use a self-generated certificate. If the sans for both differ (ie: different hostnames) then Mailpit will abort as the private and public keys won't match, so there is a little bit of repetitiveness (I know.... tradeoff of my approach). Thanks.
Author
Owner

@WilliamDEdwards commented on GitHub (Jul 24, 2025):

Tested. It works as expected! FFR, I did this:

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 48e13a1..f96dc24 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -18,8 +18,11 @@ unit test and feature test:
   stage: test
   image: python:3.11
   services:
-    - name: axllent/mailpit:v1.27
+    - name: axllent/mailpit:edge
       alias: mailpit
+      variables:
+        MP_SMTP_TLS_CERT: sans:localhost
+        MP_SMTP_TLS_KEY: sans:localhost
   script:
     - !reference [.add repositories, script]
     - ln -s .env.ci .env
diff --git a/docker-compose.yml b/docker-compose.yml
index f1d12f4..fd8971f 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,17 +2,10 @@ version: '3'
 
 services:
   mailpit:
-    image: axllent/mailpit:v1.27
+    image: axllent/mailpit:edge
     ports:
       - "8212:8025"
       - "8138:1025"
     environment:
-      MP_SMTP_TLS_CERT: /etc/ssl/certs/mailpit_cert.pem
-      MP_SMTP_TLS_KEY: /etc/ssl/private/mailpit_key.pem
-    volumes:
-      - type: bind
-        source: ./mailpit_cert.pem
-        target: /etc/ssl/certs/mailpit_cert.pem
-      - type: bind
-        source: ./mailpit_key.pem
-        target: /etc/ssl/private/mailpit_key.pem
+      MP_SMTP_TLS_CERT: sans:localhost
+      MP_SMTP_TLS_KEY: sans:localhost
<!-- gh-comment-id:3113029651 --> @WilliamDEdwards commented on GitHub (Jul 24, 2025): Tested. It works as expected! FFR, I did this: ```diff diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 48e13a1..f96dc24 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,8 +18,11 @@ unit test and feature test: stage: test image: python:3.11 services: - - name: axllent/mailpit:v1.27 + - name: axllent/mailpit:edge alias: mailpit + variables: + MP_SMTP_TLS_CERT: sans:localhost + MP_SMTP_TLS_KEY: sans:localhost script: - !reference [.add repositories, script] - ln -s .env.ci .env diff --git a/docker-compose.yml b/docker-compose.yml index f1d12f4..fd8971f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,17 +2,10 @@ version: '3' services: mailpit: - image: axllent/mailpit:v1.27 + image: axllent/mailpit:edge ports: - "8212:8025" - "8138:1025" environment: - MP_SMTP_TLS_CERT: /etc/ssl/certs/mailpit_cert.pem - MP_SMTP_TLS_KEY: /etc/ssl/private/mailpit_key.pem - volumes: - - type: bind - source: ./mailpit_cert.pem - target: /etc/ssl/certs/mailpit_cert.pem - - type: bind - source: ./mailpit_key.pem - target: /etc/ssl/private/mailpit_key.pem + MP_SMTP_TLS_CERT: sans:localhost + MP_SMTP_TLS_KEY: sans:localhost ```
Author
Owner

@axllent commented on GitHub (Jul 24, 2025):

Fantastic - thank you for testing. I plan to have this feature released this weekend.

<!-- gh-comment-id:3115244445 --> @axllent commented on GitHub (Jul 24, 2025): Fantastic - thank you for testing. I plan to have this feature released this weekend.
Author
Owner

@axllent commented on GitHub (Jul 27, 2025):

This has now been released in v1.27.2. Thanks for the suggestion and testing 👍

<!-- gh-comment-id:3123673490 --> @axllent commented on GitHub (Jul 27, 2025): This has now been released in [v1.27.2](https://github.com/axllent/mailpit/releases/tag/v1.27.2). Thanks for the suggestion and testing 👍
Author
Owner

@WilliamDEdwards commented on GitHub (Jul 27, 2025):

Thanks for your work on this Ralph!

<!-- gh-comment-id:3124244164 --> @WilliamDEdwards commented on GitHub (Jul 27, 2025): Thanks for your work on this Ralph!
Author
Owner

@axllent commented on GitHub (Jul 27, 2025):

You're very welcome, and thank you too for the sponsorship!

<!-- gh-comment-id:3124247696 --> @axllent commented on GitHub (Jul 27, 2025): You're very welcome, and thank you too for the sponsorship!
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/mailpit#346
No description provided.