0

Edit 1: After playing around further it appears that the space is not the culprit but possibly the base64url encode method is. I extracted the Raw string for both plain text and mime message and compared them in the the online tool. In case of plain text they both are same but in the case of mime message they are completely different however if I decode them back to string they are identical. I don't know a whole lot about encoding decoding so any help will be appreciated. Edit end.

I am trying to compose email in c# using mimekit and send it with google.apis.gmail.v1. but it throws error "Recipient address required[400]. Here is the code.

var mailMessage = new MailMessage
            {
                Subject = "test subject",
                Body = " <h1>test body</h1>"
            };
            mailMessage.IsBodyHtml = true;
            mailMessage.To.Add("testemail");

            MimeMessage mm = MimeMessage.CreateFromMailMessage(mailMessage);
            var gmailMessage = new Google.Apis.Gmail.v1.Data.Message
            {
                Raw = Base64UrlEncode(mm.ToString())
            };
            service.Users.Messages.Send(gmailMessage, "me").execute();
            // Encoding method
             public static string Base64UrlEncode(string text)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(text);

            return Convert.ToBase64String(bytes)
                .Replace('+', '-')
                .Replace('/', '_')
                .Replace("=", "");
        }

The above code throws error however if I compose email using plain text like below:

string plainText = "To:testemail\r\n" +
                        "Subject: test subject\r\n" +
                        "Content-Type: text/html; charset=us-ascii\r\n\r\n" +
                        "<h1>Test body<h1>";

if I encode and pass this plain text to Raw property of gmail message this works flawlessly. to debug the issue I decoded the plain text and mime message using an online tool and the only difference I notice is space before To header value like this:

// plain text:
To:testemail

//mime message:
To: testemail

notice the space after "To:". To confirm my suspicion I removed the space from mime message and encoded it again using online tool and passed the encoded string to Raw property and it works without error. So figured a hacky solution and tried removing the space using regex like this:

            var corrected = Regex.Replace(mm.ToString(), @"To: ", "To:");

But for some reason that doesn't work which doesn't make sense to me. According to the documentation Raw property takes RFC 2822 formatted and base64url encoded string and from what I could find RFC 2822 doesn't allow space after the header type. Any help will be appreciated :) For reference here is both strings decoded from raw one works and other doesn't;

//plain text that works:
To:test@test.com
Subject: Test subject
Content-Type: text/html; charset=us-ascii

<h1>Test body <h1>

// mime message that throw error
To: test@test.com
Subject: test message
Date: Date
MIME-Version: 1.0
Content-Type: text/html; charset=us-ascii

<h1>test body</h1>

Amrit
  • 13
  • 3

2 Answers2

0

Finally Solved it!! For some reason that ToString method on MimeMessage adds carriage return and new line (\r\n) at the start and end of the string representation of mime message like so "\r\n-------string---------\r\n" which apparently chokes the gmail api so I just used the trim method like so mm.ToString().Trim('\r', '\n') and voilà It works flawlessly. Not sure its a bug or a expected behavior but Jstedfast if you ever get a chance to read this post please provide your feedback.

Amrit
  • 13
  • 3
  • Looks like a bug introduced in 2.14 when I removed the code to start the message with `X-MimeKit-Warning: Do NOT use ToString()!!! Use WriteTo() instead!` when the ToString() method was called. – jstedfast Sep 13 '21 at 20:47
0

The correct solution is something more like this:

var mailMessage = new MailMessage
{
    Subject = "test subject",
    Body = " <h1>test body</h1>"
};
mailMessage.IsBodyHtml = true;
mailMessage.To.Add("testemail");

MimeMessage mm = MimeMessage.CreateFromMailMessage(mailMessage);
byte[] rawMimeData;
using (var memory = new MemoryStream ()) {
    mm.WriteTo(memory);
    rawMimeData = memory.ToArray();
}

var gmailMessage = new Google.Apis.Gmail.v1.Data.Message
{
    Raw = Base64UrlEncode(rawMimeData)
};

service.Users.Messages.Send(gmailMessage, "me").execute();

// Encoding method
public static string Base64UrlEncode(byte[] bytes)
{
    return Convert.ToBase64String(bytes)
        .Replace('+', '-')
        .Replace('/', '_')
        .Replace("=", "");
}
jstedfast
  • 35,744
  • 5
  • 97
  • 110