Andrew Truckle
Andrew Truckle

Reputation: 19087

Google Email API is raising 400 error. Recipient address required (c#)

I have seen this similar question but I am still not sure how to proceed.

Recently I upgraded my Gmail API library so I don't know if it is related.

I am getting a similar error:

<LogEntry Date="2021-08-22 12:35:10" Severity="Exception" Source="MSAToolsGMailLibrary.MSAToolsGMailLibraryClass.SendEmail" ThreadId="1">
<Exception Type="Google.GoogleApiException" Source="Google.Apis.Requests.ClientServiceRequest`1+&lt;ParseResponse&gt;d__35.MoveNext">
<Message>Google.Apis.Requests.RequestError
Recipient address required [400]
Errors [
Message[Recipient address required] Location[ - ] Reason[invalidArgument] Domain[global]
]
</Message>
<StackTrace>   at Google.Apis.Requests.ClientServiceRequest`1.&lt;ParseResponse&gt;d__35.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Google.Apis.Requests.ClientServiceRequest`1.Execute()
at MSAToolsGMailLibrary.MSAToolsGMailLibraryClass.SendEmail(String From, String Subject, String Attachment)</StackTrace>
</Exception>
</LogEntry>

This happenes even if I try my test code:

    using Message = Google.Apis.Gmail.v1.Data.Message

    public bool SendTestEmail(string From, string Subject, string Body)
    {
        try
        {
            MailMessage mail = new MailMessage();
            mail.Subject = Subject;
            mail.Body = Body;
            mail.From = new MailAddress(From);
            mail.IsBodyHtml = false;
            mail.To.Add(new MailAddress(From));
            MimeKit.MimeMessage mimeMessage = MimeKit.MimeMessage.CreateFromMailMessage(mail);

            Message message = new Message();
            message.Raw = Base64UrlEncode(mimeMessage.ToString());

            var result = m_Service.Users.Messages.Send(message, "me").Execute();
        }
        catch (Exception ex)
        {
            SimpleLog.Log(ex);
            return false;
        }

        return true;
    }

    private string Base64UrlEncode(string input)
    {
        var inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
        return Convert.ToBase64String(inputBytes)
          .Replace('+', '-')
          .Replace('/', '_')
          .Replace("=", "");
    }

I confirm that I am connected to my account with the right credentials. Never had this problem before.

Upvotes: 1

Views: 911

Answers (2)

Adam Cox
Adam Cox

Reputation: 3661

Here is what I ended up crafting for sending email:

public static Message? SendEmail(
    GmailService service,
    string subject,
    string body,
    string recipientAddress,
    string recipientName,
    GmailOptions emailOptions
    )
{
    Message? responseMessage;

    string senderAddress = emailOptions.AccountEmail;
    string senderName = emailOptions.AccountDisplayName;
    string raw;
    using (var mimeMessage = new MimeMessage
    {
        Body = new TextPart("html") { Text = body },
        Subject = subject
    }) {
        mimeMessage.To.Add(new MailboxAddress(recipientName, recipientAddress));
        mimeMessage.From.Add(new MailboxAddress(senderName, senderAddress));
        using (var stream = new MemoryStream())
        {
            mimeMessage.WriteTo(stream);
            stream.Position = 0;
            using (var reader = new StreamReader(stream))
            {
                string rawString = reader.ReadToEnd();
                byte[] rawBytes = Encoding.UTF8.GetBytes(rawString);
                raw = Convert.ToBase64String(rawBytes);
            }
        }
    }
    var messageBody = new Message() { Raw = raw };
    var sendRequest = service.Users.Messages.Send(messageBody, userId: senderAddress);
    responseMessage = sendRequest.Execute();

    return responseMessage;
}

Upvotes: 1

Andrew Truckle
Andrew Truckle

Reputation: 19087

This is the correct way to send the email:

public bool SendTestEmail(string From, string Subject, string Body)
{
    try
    {
        var mimeMessage = new MimeMessage();
        mimeMessage.From.Add(MailboxAddress.Parse(From));
        mimeMessage.ReplyTo.Add(MailboxAddress.Parse(From));
        mimeMessage.To.Add(MailboxAddress.Parse(From));
        mimeMessage.Subject = Subject;
        mimeMessage.Body = new TextPart("plain")
        {
            Text = Body
        };

        Message message = new Message();

        using (var memory = new MemoryStream())
        {
            mimeMessage.WriteTo(memory);

            var buffer = memory.GetBuffer();
            int length = (int)memory.Length;

            message.Raw = Convert.ToBase64String(buffer, 0, length);
        }

        var result = m_Service.Users.Messages.Send(message, "me").Execute();
    }
    catch (Exception ex)
    {
        SimpleLog.Log(ex);
        return false;
    }

    return true;
}

The code was kindly suggested to me by the MimeKit author on their GitHub site and they provided an explanation:

The problem with MimeMessage.ToString() is that it's often impossible to represent a MIME message entirely in 1 text encoding and so MimeKit has no choice but to use ISO-8859-1 in order to be consistent.

Internally, what ToString() does is message.WriteTo (memoryStream) and then convert the memory stream buffer into a string using the ISO-8859-1 text encoding.

If you have any non-ASCII (and non-ISO-8859-1) characters in your message, it may break things.

MimeKit, up until 2.14 or so, used to add a warning header "X-MimeKit-Warning: Do NOT use ToString()! Use WriteTo() instead!" to the top of every message if you used ToString().

Upvotes: 2

Related Questions