Kumo changing part headers with http injection

I’m generating the message content in my application and injecting messages using HTTP with content set to a string. The message generated by my code contains two ics attachment:

--8a54d64d7ad7c04a084478052b36cbe1609b33bf3a41203aaee8dd642cd3
Content-Disposition: inline; name="Invitation.ics"
Content-Transfer-Encoding: base64
Content-Type: text/calendar; method=REQUEST; name="Invitation.ics"

base64 encoded ics file data
--8a54d64d7ad7c04a084478052b36cbe1609b33bf3a41203aaee8dd642cd3
Content-Disposition: attachment; filename="event.ics"
Content-Transfer-Encoding: base64
Content-Type: application/ics

base64 encoded ics file data
--8a54d64d7ad7c04a084478052b36cbe1609b33bf3a41203aaee8dd642cd3--

The message I receive in gmail has different Content-Type and Transfer- Encoding values for the original message passed to Kumo:

--8a54d64d7ad7c04a084478052b36cbe1609b33bf3a41203aaee8dd642cd3
Content-Type: text/calendar; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
PRODID:calcom/ics
(the rest of the ics file as plaintext, not base64 as was originally delivered to kumo)

--8a54d64d7ad7c04a084478052b36cbe1609b33bf3a41203aaee8dd642cd3
Content-Type: application/ics
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="event.ics"

Tote that for the event.ics attachment / part, the original injected message had these headers:

Content-Disposition: inline; name="Invitation.ics"
Content-Transfer-Encoding: base64
Content-Type: text/calendar; method=REQUEST; name="Invitation.ics"

when sent by kumo, it was changed to

Content-Type: text/calendar; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable

and the content was changed from base64 to actual text.

Just to make sure I was not making changes to the message content in http_message_generated before sending it, I added this to the handler:

kumo.on('http_message_generated', function(msg)
  local original_sender_domain = msg:sender().domain
  local tenant = aha.cached_tenant_id(original_sender_domain)
  
  if tenant == '8b9dcfcf-94f7-477c-8372-0178618ef975' then
    local file = io.open("/tmp/msg-kumo.eml", "w")
    if file ~= nil then
      file:write(msg:get_data())
      file:close()
    end
  end

msg-kumo.eml is attached.
msg-kumo.eml (3.53 KB)

The original message (generated by my application and sent as string for content to the HTTP injection point)
msg-original.eml (3.83 KB)

the message content is effectively rebuilt by the injection logic:

the reason for that is to ensure that the parts are compliant to line length and have appropriate transfer encoding after template substitution occurs.

In theory, that should be fine, but it looks like the additional mime parameters on those ical parts (eg: method=REQUEST) are lost in the rebuild.

The change in transfer encoding should not matter, but the change in the additional parameter(s) on Content-Type feels like a surprising effect

if you manually edit the message to add back the method=REQUEST; part, does the message work/parse as you expect? I want to understand if that is sufficient to resolve this issue

Not exactly sure what you mean. At which stage should I manually add it back? the current process is:

  1. Message is generated using gomail in our backend code. At this stage it already has the method=REQUEST part.
  2. We inject it using HTTP API to Kumo - right at the beginning of the http_message_generated handler, before doing anything else, I write the contents of the message (msg:get_data()) to a file on disk - the method=REQUEST is not available in the file. Can I add it back in the handler somehow?

what I meant was, if you manually edit the message that comes out and add that method=REQUEST to the part that lost it in translation, then manually send that message on, does that message come out ok? If so, then I know that that is all that is needed to resolve the issue. If not, then we need to understand more about what it is about the message that is problematic before we can figure out how to fix it

Yes, that should fix this, the main issue is that Outlook does not show the event RSVP widget unless you send a multipart/mixed part with text/calendar; method=REQUEST Content-Type.

We were actually trying to reconstruct the message format based on what Outlook and Google send for event invitations to ensure maximum compatibility, and then noticed the method=REQUEST is getting removed.

give mailparsing: preserve supplemental Content-Type parameters on rebuild · KumoCorp/kumomta@29a99b6 · GitHub a try and let me know how you get on with it!

Seems like the build pipeline failed, the last dev release available in the apt repo is 2025.09.12.152822.f4b2ff4b

let’s see if fixup test build · KumoCorp/kumomta@e203e15 · GitHub takes care of that

Thanks Wez, the fix works perfectly. Just tested it, Outlook is showing the RSVP widget for events with method=REQUEST sent through KumoMTA.