10

Using GMail API in .Net. Creating messaging using Net.Mail.MailMessage. Then using MimeKit to create MimeMessage (using this to send attachment + HTML message). Passing MimeMessage.ToString to Base64 encoder. No API error. Code runs through ok. I can see the message in the sent page in GMail. Mail looks perfect (and the send actually return message id). But then there is the following appended message to this mail in Gmail.

Bounce <nobody@gmail.com>

An error occurred. Your message was not sent.

As usual, no other information from Google. How to fix this?

        Dim msg = New Net.Mail.MailMessage
        msg.Subject = subject
        msg.To.Add(New MailAddress(ToEmail))
        msg.From = New MailAddress(FromEmail, SenderName)
        msg.ReplyTo = New MailAddress(FromEmail, SenderName)
        msg.Body = bodyText
        msg.IsBodyHtml = True

        If Not String.IsNullOrWhiteSpace(fileAttachment) Then
            If System.IO.File.Exists(fileAttachment) Then
                Dim Attachment As New Net.Mail.Attachment(fileAttachment, "application/pdf")
                msg.Attachments.Add(Attachment)
            End If
        End If
       Dim message As MimeMessage = MimeMessage.CreateFromMailMessage(msg)
       Dim newMsg = New Google.Apis.Gmail.v1.Data.Message()
       newMsg.Raw = Base64UrlEncode(message.ToString)
       GmailService.Users.Messages.Send(newMsg, "me").Execute()



Private Function Base64UrlEncode(ByVal input As String) As String
            Dim inputBytes = System.Text.Encoding.UTF8.GetBytes(input)
            'Special "url-safe" base64 encode.
            Return Convert.ToBase64String(inputBytes).Replace("+", "-").Replace("/", "_").Replace("=", "")
        End Function

This is the return message. As you can see everything looks ok. Working with Google APIs is the most frustrating thing.

200 OK

- Hide headers -

cache-control:  no-cache, no-store, max-age=0, must-revalidate
content-encoding:  gzip
content-length:  85
content-type:  application/json; charset=UTF-8
date:  Sat, 24 Jan 2015 05:57:21 GMT
etag:  "96Z6JVARoyR8skov3RseF4DCFpA/mFWFskkdSFxyjIhRJHJuhDCBvfY"
expires:  Fri, 01 Jan 1990 00:00:00 GMT
pragma:  no-cache
server:  GSE
vary:  Origin, X-Origin

{
 "id": "14b1a841e4fff910",
 "threadId": "14b1a841e4fff910",
 "labelIds": [
  "SENT"
 ]
}
Allen King
  • 2,372
  • 4
  • 34
  • 52
  • try to get it running in the [API Explorer](https://developers.google.com/gmail/api/v1/reference/users/messages/send#try-it) first, see also http://stackoverflow.com/a/24461102/1545993 – Taifun Jan 24 '15 at 15:49
  • Same results in API Explorer. Message goes through but not delivered. Yes I read that page. I am doing exactly that. My issue is that if there is something wrong in the format, GMail API should have thrown exception. Also, the mail looks perfect when I go check in Gmail sent folder. So that means the data structure and formatting was fine. Is there a way to get in touch with these brilliant Google developers? – Allen King Jan 24 '15 at 16:54
  • Use the example message, base64 encode it and check, if you get the same result, get it first running with the API explorer... – Taifun Jan 24 '15 at 17:42

2 Answers2

6

This is crazy. This was the issue.

This line

msg.ReplyTo = New MailAddress(FromEmail, SenderName)

for whatever reasons (I guess when FromEmail and ReplyTo are same emails) leaves the RFC2822 Reply-To parameter blank. The parameter remains blank even when msg.ReplyTo is commented. Needless to say GMail API seems to have issues with Reply-To being left blank. Most definitely a programming bug.

So I had to do this hack in the final RFC2882 message.

inputTxt = Replace(inputTxt, "Reply-To:", "Reply-To: " & FromEmail)

It works now.

********* as pointed out in the comment below, you can use MailMessage.ReplyToList.Add() instead to solve this issue. So the issue here is that ReplyTo address is required in Gmail API (even though one might assume that ReplyTo should default to From email). **********

Allen King
  • 2,372
  • 4
  • 34
  • 52
  • 2
    Yes, `Reply-To` left blank is an issue. But the reason why it doesn't make it to url encoded base64 is the usage of deprecated `MailMessage.ReplyTo`. If you use `MailMessage.ReplyToList.Add()` instead, everything works fine. – jansokoly Feb 25 '15 at 00:40
3

Just in case somebody stumbles across this and wants a C# answer, here is what I was able to get working using the previous answer as a guide, with MimeKit.

public void SendEmail(MyInternalSystemEmailMessage email)
{
    var mailMessage = new System.Net.Mail.MailMessage();
    mailMessage.From = new System.Net.Mail.MailAddress(email.FromAddress);
    mailMessage.To.Add(email.ToRecipients);
    mailMessage.ReplyToList.Add(email.FromAddress);
    mailMessage.Subject = email.Subject;
    mailMessage.Body = email.Body;
    mailMessage.IsBodyHtml = email.IsHtml;

    foreach (System.Net.Mail.Attachment attachment in email.Attachments)
    {
        mailMessage.Attachments.Add(attachment);
    }

    var mimeMessage = MimeKit.MimeMessage.CreateFromMailMessage(mailMessage);

    var gmailMessage = new Google.Apis.Gmail.v1.Data.Message {
        Raw = Encode(mimeMessage.ToString())
    };

    Google.Apis.Gmail.v1.UsersResource.MessagesResource.SendRequest request = service.Users.Messages.Send(gmailMessage, ServiceEmail);

    request.Execute();
}

public static string Encode(string text)
{
    byte[] bytes = System.Text.Encoding.UTF8.GetBytes(text);

    return System.Convert.ToBase64String(bytes)
        .Replace('+', '-')
        .Replace('/', '_')
        .Replace("=", "");
}
Xtros
  • 467
  • 5
  • 9