mirror of
https://github.com/axllent/mailpit.git
synced 2026-04-27 01:06:01 +03:00
[GH-ISSUE #456] Add option to include full Message in /api/v1/search #294
Labels
No labels
awaiting feedback
bug
docker
documentation
enhancement
github_actions
invalid
pull-request
question
stale
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/mailpit#294
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @buschtoens on GitHub (Mar 5, 2025).
Original GitHub issue: https://github.com/axllent/mailpit/issues/456
The
/api/v1/searchendpoint only returns aMessageSummaryas opposed to the/api/v1/message/{ID}endpoint, which returns the fullMessage.I think this is a very sensible default, however it makes the API annoying to consume for the following use case: You're searching for a single specific message and need its full
Message.Textinstead of just theMessageSummary.Snippet.Currently you have to perform two API requests to do this:
/api/v1/searchto find the mail and get itsID./api/v1/message/{ID}to retrieve theMessage.Text.I would love a
summary=false(defaulttrue) or alternativelyfull=true(defaultfalse) query parameter on the/api/v1/searchendpoint that toggles returningMessagestructs instead ofMessageSummary.Do you think this would be a good addition? I'm happy to try my hand at a PR, but wanted to get your perspective first.
Thanks for the great project!
@axllent commented on GitHub (Mar 6, 2025):
Thank you for the feedback @buschtoens. I do understand what you are asking, however I don't think it is that easy (nor a good idea), I'll explain:
MessageSummarystruct. The database also includes a "fulltext search" field which is used only for the search itself. Returning results for this data is fast because Mailpit does not have to process anything, it just reads the results into the struct and returns the struct as JSON./api/v1/message/{ID}), which includes text & HTML, is stored compressed in a separate table. The raw message is what gets parsed every time to populate theMessagestruct when an individual message is read. This includes reading the compressed data from the database, extracting & of course parsing it. This process is by far far the most CPU & RAM intensive action in Mailpit.What you are suggesting would effectively require:
full=truequery parameter) would require both a new struct type, and complicate the REST API response (ie: it would need to account for the potential of two separate response types via the same API route)full=true) would need to be parsed in order to complete the response. This may be OK if you're only dealing with a few small messages, but this becomes extremely heavy when dealing with multiple results, not to mention if the messages are large. If you have a mailbox filled with with hundreds of 25MB messages, and Mailpit takes 0.5 seconds to parse just one of those messages.... then Mailpit becomes an extremely heavy, slow application with huge CPU & RAM overheads, all the things Mailpit was designed to avoid. I think you see where this is going...The only way this could work efficiently is if Mailpit stored a complete separate copy of the HTML and text of every message, which would mean the database size would increase. Then the next user wants a list of the attachments in that
full=trueresponse, the next wants a full set of headers....So do I think this is a good addition? Unfortunately, no. I believe it would heavily complicate how Mailpit works internally, increase the CPU & RAM usage, and complicate the simple REST API (potentially confusing users in the process). In order to try reduce the CPU & RAM overheads, I would need to drastically change how messages are stored, complicating the controller functions and increasing the database size (not to mention handle all existing data). All of this just to save an additional API request.
Sorry, I really don't like turning down requests (especially when I can understand the user's perspective), however I think the downsides of implementing this far outweigh the benefits.
Can you please explain to me why an extra API request is annoying? Surely whatever you are using the API for is automated?
@buschtoens commented on GitHub (Mar 6, 2025):
Thank you so much for this very thoughtful and thorough response! I really appreciate it.
I can clearly see now, why this wouldn't be trivially possible and not even a good idea! 😄
Yes, you had the right hunch.
We are in the process of migrating over from
fake-smtp-server. For everything it lacked in features and performance (ding!), it had one nice thing going for it:The API allowed searching and always returned the full message. Now this likely contributed to the general slowness we experienced, but it made it super convenient for direct consumption in automated tests across different languages & testing frameworks.
In our use-case we only ever needed the most recent message that matches anyway, akin to a "find" operation.
Do you think adding something like
/api/v1/findwould be a sensible alternative?It would accept a
query&tzand search for the most recent message that matches, then return it as a single fullMessage.If none matches,
404is returned.This could optionally accept a
sortparameter, to cover cases, where you wouldn't necessarily want to pick the most recent message.@axllent commented on GitHub (Mar 6, 2025):
Is that the latest message, or the latest message from a specific search? If it's the latest message (ie: the last message Mailpit received), then you can just call
/api/v1/message/latestOne challenge I have is not adding features for the sake of adding them, because once they are in the codebase it is effectively impossible to remove them. I'm still confused as to why a second API call is so inconvenient though? The search, which is already very flexible, returns the results (overview), and to get the information you require just requires another call.
@buschtoens commented on GitHub (Mar 6, 2025):
The latest message matching the search query.
/api/v1/find?query=subject:"Your+OTP"+to:foo@example.orgI agree that it’s not a necessary feature. Everything this feature offers functionally can already be achieved with today’s API.
Maybe my perception is skewed, because I’m approaching this from an automated testing angle, but in my previous experience the interaction between tests and Mailpit / fake-smtp-server is reduced to just a single task: finding the most recent matching mail to then extract information out of the body.
For this particular scenario (which I imagine common) such a proposed endpoint would be convenient and save a round-trip, marginally speeding up the test.
If you think the benefit / usefulness in the wild will not be as great as to outweigh the burden of maintaining this endpoint, I can accept that and continue working with the two-request solution. :)
@axllent commented on GitHub (Mar 6, 2025):
While I would love to incorporate every requested feature, I genuinely believe that the benefits do not justify the overhead of implementation and maintenance. I try to avoid saying "never," as I've been proven wrong in the past when I initially declined a request only to add it much later, but it was usually driven by demand and often as part of a larger related feature. However, this particular feature seems to only serve the purpose of saving an additional HTTP request and a JSON parse, and doesn't add any actual functionality that isn't already there, be it in a two-step process instead of one.
Given the daily Docker pull counts, it seems reasonable to conclude that Mailpit is very widely utilized in automated testing. Although I can't support this assumption with specific statistics (as Mailpit does not track any usage), I believe it likely involves a combination of direct
latestpulls along with search and regular API calls.I do however appreciate the fact you're using Mailpit!