13

I'm looking at using the Gmail API in an application I'm working on. However, I'm not sure how to change their Java or Python examples over to C#. How exactly does the existing sample change over?

Sample found here.

muttley91
  • 12,278
  • 33
  • 106
  • 160
  • 3
    Java is so close to C#, surely you've tried to convert it and have failed some how? Perhaps posting what you've tried to convert would be a good start for people to help you where you're wrong – Prescott Jul 14 '14 at 03:25
  • Well I'm looking for equivalents to `MimeMessage`, `Properties`, etc. and quick Googling didn't help with that. – muttley91 Jul 14 '14 at 04:17
  • Google APIs are all REST APIs. The docs are telling you what parameters need to go into your REST API calls. – Casey Jul 14 '14 at 20:14

3 Answers3

22

Here is what I was able to get working, using 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)
    };

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

    request.Execute();
}

public static string Encode(MimeMessage mimeMessage)
{
    using (MemoryStream ms = new MemoryStream())
    {
        mimeMessage.WriteTo(ms);
        return Convert.ToBase64String(ms.GetBuffer())
            .TrimEnd('=')
            .Replace('+', '-')
            .Replace('/', '_');
    }
}

}

Note: If you are getting an email bounce issue, it is likely due to not setting the ReplyToList field. See: GMail API Emails Bouncing

thankyoussd
  • 1,875
  • 1
  • 18
  • 39
Xtros
  • 467
  • 5
  • 9
  • 2
    I don't think you should use `mimeMessage.ToString()`. According to Remarks in `namespace MimeKit`: `In general, the string returned from this method SHOULD NOT be used for serializing the message to disk. It is recommended that you use MimeKit.MimeMessage.WriteTo(System.IO.Stream,System.Threading.CancellationToken) instead.` – Doan Van Thang Feb 01 '21 at 08:02
  • @DoanVanThang Yeah, that's possible. It might have changed in the last five years, or maybe it always should have been that way. Thanks for the tip! – Xtros Feb 02 '21 at 14:58
  • 2
    I had a issue with mimeMessage.ToString(). The characters ã ç ã á .. wouldn´t come right. I found a solution at: https://stackoverflow.com/questions/55402719/sending-email-with-gmail-api-encoding-greek-characters-in-body – ChrCury78 Jun 16 '21 at 19:12
  • I can confirm that as if 07/2021, using the latest version of MimeKit and Gmail API SDK, the `mimeMessage.ToString()` approach simply won't work (API returns "Recipient Address Required" error). The link posted by @ChrCury78 (https://stackoverflow.com/questions/55402719/sending-email-with-gmail-api-encoding-greek-characters-in-body) has the working solution (writing the `MimeMessage` to stream instead of using `ToString()`). This answer should be updated with the provided code. It took me hours to figure out. – thankyoussd Jul 30 '21 at 06:06
  • @thankyoussd The answer does list an update with a link to that question and the comments mention it. Sorry that it took you hours, but I think reading the whole answer would have helped. – Xtros Jul 30 '21 at 20:08
  • @thankyoussd Because I haven't written that code and have not verified it, nor am I going to. The linked question answers the specific issue you were having. Unfortunately, answers can't be a living document that are maintained with every update of a library. This answer worked 5 years ago when it was posted. – Xtros Jul 30 '21 at 20:13
  • I submitted an edit request. The code has been verified to work. – thankyoussd Jul 30 '21 at 20:18
7

This was a tricky problem to solve, but I did end up getting it. I used the NuGet package AE.Net.Mail to get the RFC 2822 bit.

using System.IO;
using System.Net.Mail;
using Google.Apis.Gmail.v1;
using Google.Apis.Gmail.v1.Data;

public class TestEmail {

  public void SendIt() {
    var msg = new AE.Net.Mail.MailMessage {
      Subject = "Your Subject",
      Body = "Hello, World, from Gmail API!",
      From = new MailAddress("[you]@gmail.com")
    };
    msg.To.Add(new MailAddress("yourbuddy@gmail.com"));
    msg.ReplyTo.Add(msg.From); // Bounces without this!!
    var msgStr = new StringWriter();
    msg.Save(msgStr);

    var gmail = new GmailService(MyOwnGoogleOAuthInitializer);
    var result = gmail.Users.Messages.Send(new Message {
      Raw = Base64UrlEncode(msgStr.ToString())
    }, "me").Execute();
    Console.WriteLine("Message ID {0} sent.", result.Id);
  }

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

Same code with a little further analysis and reasons are posted here: http://jason.pettys.name/2014/10/27/sending-email-with-the-gmail-api-in-net-c/

pettys
  • 2,293
  • 26
  • 38
  • I tried using your code, however I get the error error CS0103: The name 'Context' does not exist in the current context on Context.GoogleOAuthInitializer. Where are you getting Context from? – Rossini Nov 18 '14 at 15:32
  • @Rossini Sorry for the confusion there -- that is a reference to my own code that returns a Google.Apis.Services.BaseClientService.Initializer that is set up to add the OAuth2 Bearer token to each request. You might be able to just use the default GmailService() constructor -- depends on how your GmailService is authenticating. I'll update my code to try to make that more clear. – pettys Nov 18 '14 at 18:57
  • 1
    This code works ok for a plain text email. But doesn't work with HTML email + attachment. – Allen King Jan 24 '15 at 04:37
  • 1
    For anyone looking at this in the future, make sure you are using the `AE.Net.Mail` Nuget Package (https://www.nuget.org/packages/AE.Net.Mail/) and not `System.Net.Mail` (https://msdn.microsoft.com/en-us/library/system.net.mail(v=vs.110).aspx). They are *very* similar, but work slightly differently (e.g. `System.Net.Mail.MailMessage` doesn't have the `Save` method) – derekantrican Jun 09 '17 at 19:26
-1

Seems like this isn't really an issue with the Gmail API. What you should be looking for is "c# create email" (potentially adding "RFC 2822" as that's the RFC that defines the format for these emails). Once you have such a valid "email message" (the real, entire email content you can use with SMTP or IMAP, etc) then using it with the Gmail API should be pretty trivial.

Eric D
  • 6,901
  • 1
  • 15
  • 26
  • 1
    You're right. I posted under Gmail API thinking that someone might have come across this before and had an answer, but I should direct it more towards C#. Thanks. – muttley91 Jul 14 '14 at 19:34
  • @rar Did you find anything? Trying to solve the same problem. – pettys Oct 27 '14 at 23:39
  • 1
    Unfortunately not. We had to abandon Gmail API as it wasn't working out and we didn't have a lot of time to spend on it when we could just use a simpler email sender. Google could really stand to improve their documentation on this... – muttley91 Oct 27 '14 at 23:48
  • 1
    @rar Thanks for the response. I was able to finally get the raw RFC 2822 message bytes using nuget package AE.Net.Mail - https://github.com/andyedinborough/aenetmail. I know what you mean about the Gmail API -- took me all day to finally get it to send a message. – pettys Oct 28 '14 at 00:35
  • rar/pettys: what exactly was the problem that you weren't able to figure out or how could docs be better improved? The hardest part IMO seems to be creating an email message and that's not really specific to the API, you need to do the same whether you're using SMTP or the API or IMAP. Once you have the email message string just base64url encoding it and POSTing it to the right URL is pretty trivial and there's good java code showing it. – Eric D Oct 28 '14 at 19:37