KumoCorp / kumomta

The first Open-Source high-performance MTA developed from the ground-up for high-volume email sending environments.
https://kumomta.com
Apache License 2.0
225 stars 28 forks source link

Get (and/or) modify MIME parts as variables #117

Open tommairs opened 8 months ago

tommairs commented 8 months ago

The problem: There are times when you need to modify a message before delivery, and at this time, it is doable but cumbersome. For instance, adding an open image link to the HTML part is currently a bit of a chore. It would be helpful to modify a message body to get the MIME parts as variables in the same way you can get a table of headers. Ideally, you can also modify the MIME part and reassemble the message before delivery, but that may be a separate enhancement ticket.

The current situation: Take the above suggested open tracking image, for instance. At this time, you need to capture the entire message in a variable, modify it, and reinject it. EG:

local msg_body = msg:get_data()
    -- update body here

     -- define and add tracking link to HTML part
    local my_tracking_link = '<img src="http://10.0.0.1/img_tracker.jpg" alt="open tracking pixel">'
    msg_body = msg_body:gsub("</body>", my_tracking_link .. " </body>")

    local msg_payload = kumo.json_encode {
      envelope_sender = msg:sender().email,
      content = msg_body,
      recipients = {
        { email = msg:recipient().email },
      },
    }

The above is a straightforward example and is error-prone.

Suggested enhancement: If there were a function to get the message parts into a table that could be modified, it would simplify the process and reduce errors. Something like msg:get_mime_parts() might result in a table of all the MIME parts that could then be manipulated, like:

{"text":"there is nothing here","html":"<body><p>There is HTML here</p></body>"}

Now I can modify or entirely replace a MIME part without accidentally changing others.

Other Considerations: The opposite (set_) is valid in that assembling a message should be the reverse. Something like this would be handy:

msg:set_mime_parts("text":"there is nothing here","html":"<body><p>There is _new_ HTML here</p></body>")
wez commented 8 months ago

FWIW, it's "impossible" to make this allow editing of parts by reference. The most likely form of this API will be:

{
  text = {
    headers = { --[[ a table containing a list of headers ]] },
    content = [[ The content decoded to UTF8 ]],
  },
  html = {
    headers = { --[[ a table containing a list of headers ]] },
    content = [[ The content decoded to UTF8 ]],
  },
  attachments = {
    -- [[ table of attachment data ]]
  }
}

Then a separate function to optionally replace the payload. Name TBD, but:

It may also be worth the effort to produce a special ParsedMime type for lua to better encapsulate this, so that handling of headers per part, per attachment and so on is well defined and convenient.

There's a decent amount of work to make this general.

However, if there are some well-defined, well-constrained, targeted use cases, building support for those is likely simpler and easier.