msgraph-sdk-go icon indicating copy to clipboard operation
msgraph-sdk-go copied to clipboard

Is there a way to post a raw RFC 5322 message to the create message endpoint?

Open dcormier opened this issue 1 year ago • 2 comments
trafficstars

I have an RFC 5322-formatted message, and I'm trying to POST it to the /users/{id | userPrincipalName}/mailFolders/{id}/messages endpoint.

Per the docs for that API, that is possible when POSTing a request to that endpoint with a content type of text/plain. Specifically, this note in the "Request headers" section for Content-Type (emphasis mine):

Use application/json for a JSON object and text/plain for MIME content.

Combined with this additional note in the "Request body" section:

When specifying the body in MIME format, provide the MIME content with the applicable Internet message headers ("To", "CC", "BCC", "Subject"), all encoded in base64 format in the request body.

I can't find a way to do this with the SDK. Am I missing something, or does the SDK not support this?

I'm able to get as far as this:

client.
	Users().
	ByUserId(userID).
	MailFolders().
	ByMailFolderId("inbox").
	Messages().
	Post(
		ctx,
		// This doesn't compile as it isn't `model.Messageable`.
		// How do I send this?
		base64.StdEncoding.EncodeToString(email),
		nil,
	)

A model.Messaage gets sent as application/json, and can't be built from an RFC 5322 message (as far as I can tell).

dcormier avatar May 01 '24 13:05 dcormier

Hi @dcormier, Thanks for trying the MS Graph Go SDK. As of now , v1.44.0 of graph go sdk, it does not support sending RFC 5322-formatted message. You should still be able to parse this message to a 'MessageObject' and send it via the SDK.

Here is some sample code

package main

import (
	"bytes"
	"fmt"
	"log"
	"net/mail"
	"strings"
)

// Message represents an email message.
type Message struct {
	From    string
	To      []string
	Cc      []string
	Bcc     []string
	Subject string
	Date    string
	Body    string
}

func parseRFC5322Message(rfc5322 string) (*Message, error) {
	// Create a reader for the message string
	reader := strings.NewReader(rfc5322)

	// Parse the message using the net/mail package
	msg, err := mail.ReadMessage(reader)
	if err != nil {
		return nil, err
	}

	// Extract the headers
	header := msg.Header

	// Get the values of the headers
	from := header.Get("From")
	to := header.Get("To")
	cc := header.Get("Cc")
	bcc := header.Get("Bcc")
	subject := header.Get("Subject")
	date := header.Get("Date")

	// Read the body
	bodyBuffer := new(bytes.Buffer)
	bodyBuffer.ReadFrom(msg.Body)
	body := bodyBuffer.String()

	// Split the "To", "Cc", and "Bcc" headers into slices
	toList := parseAddressList(to)
	ccList := parseAddressList(cc)
	bccList := parseAddressList(bcc)

	// Create the message model
	message := &Message{
		From:    from,
		To:      toList,
		Cc:      ccList,
		Bcc:     bccList,
		Subject: subject,
		Date:    date,
		Body:    body,
	}

	return message, nil
}

func parseAddressList(addresses string) []string {
	if addresses == "" {
		return []string{}
	}
	// Split the address list by commas and trim spaces
	list := strings.Split(addresses, ",")
	for i := range list {
		list[i] = strings.TrimSpace(list[i])
	}
	return list
}


rkodev avatar May 30 '24 09:05 rkodev

An approach like that won't work in this case because of subtle differences between MIME content and JSON representations. There are too many emails that don't adhere strictly to the RFCs. We need byte for byte precision for these emails. We need to be able to post the MIME content directly. We don't want this code to be pointed at for any discrepancies.

dcormier avatar May 30 '24 13:05 dcormier