[GH-ISSUE #563] [Feature request] Add more control over iframe content with <base href="https://example.tld/app/"> #363

Closed
opened 2026-03-15 14:05:25 +03:00 by kerem · 7 comments
Owner

Originally created by @baiomys on GitHub (Sep 8, 2025).
Original GitHub issue: https://github.com/axllent/mailpit/issues/563

Hi.

First of all, thank you very much for adding the ?embed parameter to control links. Besides that, it would be great to add the ability to set a <base href=> tag, which would allow loading the iframe directly from different Mailpit instances without redirects and other complications under the hood.

Thank you.

Originally created by @baiomys on GitHub (Sep 8, 2025). Original GitHub issue: https://github.com/axllent/mailpit/issues/563 Hi. First of all, thank you very much for adding the ?embed parameter to control links. Besides that, it would be great to add the ability to set a <base href=> tag, which would allow loading the iframe directly from different Mailpit instances without redirects and other complications under the hood. Thank you.
kerem closed this issue 2026-03-15 14:05:30 +03:00
Author
Owner

@axllent commented on GitHub (Sep 8, 2025):

Hi @baiomys - I need more detail about your infrastructure to understand exactly what you're asking for. Right now it sounds like you're asking for Mailpit to handle these complications introduced by your app again, but I can't be sure. Please describe your setup and why you think base should be configurable (I cannot see how it should ever be needed, in fact I remove base if it exists in an HTML email for security purposes), otherwise I'm left guessing.

<!-- gh-comment-id:3264529573 --> @axllent commented on GitHub (Sep 8, 2025): Hi @baiomys - I need more detail about your infrastructure to understand exactly what you're asking for. Right now it sounds like you're asking for Mailpit to handle these complications introduced by your app again, but I can't be sure. Please describe your setup and why you think `base` should be configurable (I cannot see how it should ever be needed, in fact I remove `base` if it exists in an HTML email for security purposes), otherwise I'm left guessing.
Author
Owner

@baiomys commented on GitHub (Sep 8, 2025):

With the URL passed as the /view? parameter it would become possible to load the main message viewer page with a single set of JS and CSS directly from a CDN - from one place - and set the iframe src to the URLs of many Mailpit instances. It would keep local links inside iframe working.

There is a 100% safe way to implement this. User can define external base URL into the instance parameters, since it shouldn't change dynamically during the instance lifetime. Then enable it by passing a parameter like /view?altbase (or reuse ?embed), which isn't ideal but would work.

<!-- gh-comment-id:3265498423 --> @baiomys commented on GitHub (Sep 8, 2025): With the <base href> URL passed as the /view? parameter it would become possible to load the main message viewer page with a single set of JS and CSS directly from a CDN - from one place - and set the iframe src to the URLs of many Mailpit instances. It would keep local links inside iframe working. There is a 100% safe way to implement this. User can define external base URL into the instance parameters, since it shouldn't change dynamically during the instance lifetime. Then enable it by passing a parameter like /view?altbase (or reuse ?embed), which isn't ideal but would work.
Author
Owner

@axllent commented on GitHub (Sep 9, 2025):

Unfortunately I still do not understand your implementation as you haven't actually explained your architecture.

Your iframe on example1.com has a src="http://example2.com/view/3qGR5mX4AVnX3PJfS4GqhQ?embed=1" attribute, meaning the browser is fetching the entire content of the iframe from http://example2.com/view/3qGR5mX4AVnX3PJfS4GqhQ?embed=1. Any links within that iframe HTML would be relative to http://example2.com/, so if an image referenced within that iframe HTML was embedded as <img src="/api/v1/message/bGFAfyBd7kG8iQh3hUBFDK/part/2.2"> then the browser would fetch it from http://example2.com/api/v1/message/bGFAfyBd7kG8iQh3hUBFDK/part/2.2.

So if you set the iframe URL to http://api1.com/view/3qGR5mX4AVnX3PJfS4GqhQ?embed=1 then message assets get requested from api1.com, if you set it to http://api2.com/view/3qGR5mX4AVnX3PJfS4GqhQ?embed=1 then the message assets get requested from api2.com.

I still do not understand why any base is needed.

<!-- gh-comment-id:3268849733 --> @axllent commented on GitHub (Sep 9, 2025): Unfortunately I still do not understand your implementation as you haven't actually explained your architecture. Your iframe on example1.com has a `src="http://example2.com/view/3qGR5mX4AVnX3PJfS4GqhQ?embed=1"` attribute, meaning the browser is fetching the entire content of the iframe from `http://example2.com/view/3qGR5mX4AVnX3PJfS4GqhQ?embed=1`. Any links within that iframe HTML would be relative to `http://example2.com/`, so if an image referenced within that iframe HTML was embedded as `<img src="/api/v1/message/bGFAfyBd7kG8iQh3hUBFDK/part/2.2">` then the browser would fetch it from `http://example2.com/api/v1/message/bGFAfyBd7kG8iQh3hUBFDK/part/2.2`. So if you set the iframe URL to `http://api1.com/view/3qGR5mX4AVnX3PJfS4GqhQ?embed=1` then message assets get requested from `api1.com`, if you set it to `http://api2.com/view/3qGR5mX4AVnX3PJfS4GqhQ?embed=1` then the message assets get requested from `api2.com`. I still do not understand why any `base` is needed.
Author
Owner

@baiomys commented on GitHub (Sep 9, 2025):

It will work only if the URIs are exactly the same, which is not always the case.
Anyway, if you feel that adding a base is unnecessary, no problem.

P.S. There is one more issue, I am using JWT tokens with payload to validate email queries. I can pass JWT to base URL as src="http://example2.com/view/3qGR5mX4AVnX3PJfS4GqhQ?embed=1&tk=someJWT, but all other links inside email will fail.

iframe cookie assignment from query parameter /view?cookie=name[separator]value should do the trick

<!-- gh-comment-id:3269161128 --> @baiomys commented on GitHub (Sep 9, 2025): It will work only if the URIs are exactly the same, which is not always the case. Anyway, if you feel that adding a base is unnecessary, no problem. P.S. There is one more issue, I am using JWT tokens with payload to validate email queries. I can pass JWT to base URL as src="http://example2.com/view/3qGR5mX4AVnX3PJfS4GqhQ?embed=1&tk=someJWT, but all other links inside email will fail. iframe cookie assignment from query parameter /view?cookie=name[separator]value should do the trick
Author
Owner

@axllent commented on GitHub (Sep 9, 2025):

It will work only if the URIs are exactly the same, which is not always the case. Anyway, if you feel that adding a base is unnecessary, no problem.

I don't understand what that means ("only if the URIs are exactly the same"), however the bigger issue here is that I still don't understand your infrastructure despite two separate requests for more information. I get the impression you aren't sharing that because it's confidential, which is fine, but I can't help you because I don't understand the problem or see how a base would help at all. It's as simple as that.

So if you're not going to answer my questions and provide me detailed information, then please just close this issue.

<!-- gh-comment-id:3269430473 --> @axllent commented on GitHub (Sep 9, 2025): > It will work only if the URIs are exactly the same, which is not always the case. Anyway, if you feel that adding a base is unnecessary, no problem. I don't understand what that means ("only if the URIs are exactly the same"), however the bigger issue here is that I still don't understand your infrastructure despite two separate requests for more information. I get the impression you aren't sharing that because it's confidential, which is fine, but I can't help you because I don't understand the problem or see how a `base` would help at all. It's as simple as that. So if you're not going to answer my questions and provide me detailed information, then please just close this issue.
Author
Owner

@baiomys commented on GitHub (Sep 9, 2025):

I can handle lack of BASE setting in iframe, not a problem anymore, will use subdomains instead.
Pls suggest how to solve JWT passthrough issue.

I get the impression you aren't sharing that because it's confidential,

Not at all. =)
JS code on the page makes a request to the API and, roughly speaking, receives the Mailpit instance URL and a JWT containing the message UUID and timestamp.
Because there may be more than one bot, and there are already around a dozen Mailpit instances - all coordinated from a single endpoint - some complications arise.

<!-- gh-comment-id:3269447059 --> @baiomys commented on GitHub (Sep 9, 2025): I can handle lack of BASE setting in iframe, not a problem anymore, will use subdomains instead. Pls suggest how to solve JWT passthrough issue. > I get the impression you aren't sharing that because it's confidential, Not at all. =) JS code on the page makes a request to the API and, roughly speaking, receives the Mailpit instance URL and a JWT containing the message UUID and timestamp. Because there may be more than one bot, and there are already around a dozen Mailpit instances - all coordinated from a single endpoint - some complications arise.
Author
Owner

@axllent commented on GitHub (Sep 9, 2025):

I don't have a clue, sorry. Mailpit doesn't use JWT tokens, nor does it provide either a /api/waauth or /api/v1/message/view endpoint, so I do not understand what I am looking at here 🤷‍♂️

At a guess you are trying to abstract the backend(s) from the frontend - couldn't you just proxy the API calls directly through to the Mailpit instance instead? If everything on your frontend from /api/v1/* was proxied through to the backend Mailpit instance then you would not need to use JWT, and the proxy could even handle basic auth to Mailpit without requiring the frontend / JWT authentication. For example https://example.com/api/v1/message/bGFAfyBd7kG8iQh3hUBFDK/part/2.2 just proxies to https://example2.com/api/v1/message/bGFAfyBd7kG8iQh3hUBFDK/part/2.2 using nginx or whatever, and adds a basic authentication header to the proxies request. The user just interacts with https://example.com/ and doesn't even know about https://example2.com/.

<!-- gh-comment-id:3269821801 --> @axllent commented on GitHub (Sep 9, 2025): I don't have a clue, sorry. Mailpit doesn't use JWT tokens, nor does it provide either a `/api/waauth` or `/api/v1/message/view` endpoint, so I do not understand what I am looking at here 🤷‍♂️ At a guess you are trying to abstract the backend(s) from the frontend - couldn't you just proxy the API calls directly through to the Mailpit instance instead? If everything on your frontend from `/api/v1/*` was proxied through to the backend Mailpit instance then you would not need to use JWT, and the proxy could even handle basic auth to Mailpit without requiring the frontend / JWT authentication. For example `https://example.com/api/v1/message/bGFAfyBd7kG8iQh3hUBFDK/part/2.2` just proxies to `https://example2.com/api/v1/message/bGFAfyBd7kG8iQh3hUBFDK/part/2.2` using nginx or whatever, and adds a basic authentication header to the proxies request. The user just interacts with `https://example.com/` and doesn't even know about `https://example2.com/`.
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#363
No description provided.