0

I am adapting an application to send out emails through GMail and I thought I might use the Google API to do it. I have the API library from here; https://github.com/googleapis/google-api-dotnet-client

The Github repo and linked developers.google.com and googleapis.dev pages dont really have a lot of good examples of the usage of the API, at least for Gmail so far as I can see.

I have a message creating method:

        private Message CreateCustomerMessage()
        {
            var customerBody = GenerateCustomerMessageBody();
            var customerMessage = new Message
            {
                Payload = new MessagePart
                {
                    Headers = new List<MessagePartHeader>() {
                        new MessagePartHeader() { Name = "From", Value = "\"Reservation Service\" <reservations@domain.com>"},
                        new MessagePartHeader() { Name = "To", Value = Reservation.PartyEmail },
                        new MessagePartHeader() { Name = "Content-type", Value = "text/html; charset=iso-8859-1" }
                    },
                    Body = new MessagePartBody
                    {
                        Data = customerBody.ToBase64Url()
                    },
                    Parts = new List<MessagePart>()
                    {
                        new MessagePart()
                        {
                            Filename = "Trip_Calendar.ics",
                            Body = new MessagePartBody(){ Data = CreateShuttleCalendarEvent(customerBody).ToBase64Url() },
                            Headers = new List<MessagePartHeader>()
                            {
                                new MessagePartHeader() { Name = "Content-type", Value = "text/calendar"}
                            }
                        }
                    }
                }
            };
            return customerMessage;
        }

I am creating the body in a separate method call, creating the Message with a Payload wherein the Body is set to the Base64Url encoded body generated above. Also setting headers and so forth.

Additionally I am creating a calendar file and attaching it.

Upon passing the message to the Send() method, I get the following exception message:

The service gmail has thrown an exception. HttpStatusCode is BadRequest. 'raw' RFC822 payload message string or uploading message via /upload/* URL required

I had hoped that the issue was just with the calendar file, but removing that and sending returned the same exception.

I have seen posts saying that you can construct the raw email message complete with all of the headers in a string and attach that to the message instead of constructing it with the MessageParts and whatnot. I was hoping to use this API library the way it was intended to be used, but if I have to do it with the raw message I suppose I will. Are there any good examples that anyone might know of showing how these Google API Library classes are supposed to be used? Personally the above method looks nice and clean and does not rely on a large string interpolation with injected values.

Edit

I do not consider this a duplicate of the above linked post. The above posts answers create the message with System.Net.Mail.MailMessage and AE.Net.Mail.MailMessage rather than using the API supplied classes. My post was specifically asking about how the API Library was meant to be used. Those classes are there for a reason. Presumably they are meant to be used to send mail. Why aren't they? Are they broken functionality when sending? Is the expected method to use some other class to construct the mail message then output the raw and attach it to the Gmail Message class instance? That seems counter intuitive to me. I would appreciate my post being restored and no longer marked as duplicate.

CodeWarrior
  • 7,388
  • 7
  • 51
  • 78
  • I posted below using the Google API. Check it out. – mathis1337 Aug 20 '22 at 02:41
  • But you are constructing the mail message with MimeMessage and then outputting to attach to the Raw property. Is the Google API class not meant to be used to construct the message rather than have it pre-digested by another class and handed to it as Raw? – CodeWarrior Aug 20 '22 at 02:44

1 Answers1

4

Here is how I do it using Google.Apis.Gmail.v1

using Google.Apis.Auth.OAuth2;
using Google.Apis.Gmail.v1;
using Google.Apis.Gmail.v1.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using MimeKit;

void Main()
{
    UserCredential credential;

    using (var stream =
        new FileStream(@"D:\credentials.json", FileMode.Open, FileAccess.Read))
    {
        // The file token.json stores the user's access and refresh tokens, and is created
        // automatically when the authorization flow completes for the first time.
        string credPath = "token.json";
        credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
            GoogleClientSecrets.Load(stream).Secrets,
            Scopes,
            "user",
            CancellationToken.None,
            new FileDataStore(credPath, true)).Result;
        Console.WriteLine("Credential file saved to: " + credPath);
    }

    // Create Gmail API service.
    var service = new GmailService(new BaseClientService.Initializer()
    {
        HttpClientInitializer = credential,
        ApplicationName = ApplicationName,
    });

    // Define parameters of request.
    UsersResource.LabelsResource.ListRequest request = service.Users.Labels.List("me");

    // List labels.
    IList<Label> labels = request.Execute().Labels;
    Console.WriteLine("Labels:");
    if (labels != null && labels.Count > 0)
    {
        foreach (var labelItem in labels)
        {
            Console.WriteLine("{0}", labelItem.Name);
        }
    }
    else
    {
        Console.WriteLine("No labels found.");
    }
    //Console.Read();
    var msg = new Google.Apis.Gmail.v1.Data.Message();
    MimeMessage message = new MimeMessage();
    
    message.To.Add(new MailboxAddress("", "ToEmail@gmail.com"));
    message.From.Add(new MailboxAddress("Gmail Name", "someGmailFromEmail@gmail.com"));
    message.Subject = "Test email with Mime Message";
    message.Body = new TextPart("html") {Text = "<h1>This</h1> is a body..."};
    
    var ms = new MemoryStream();
    message.WriteTo(ms);
    ms.Position = 0;
    StreamReader sr = new StreamReader(ms);
    string rawString = sr.ReadToEnd();

    byte[] raw = System.Text.Encoding.UTF8.GetBytes(rawString);
    msg.Raw = System.Convert.ToBase64String(raw);
    
    var res = service.Users.Messages.Send(msg, "me").Execute();
    
    res.Dump();


}
static string[] Scopes = { GmailService.Scope.GmailSend, GmailService.Scope.GmailLabels, GmailService.Scope.GmailCompose, GmailService.Scope.MailGoogleCom};
static string ApplicationName = "Gmail API Send Email";

Basically within the gmail app create the credentials.json. From there you can now produce a token.json file that will allow you to send email from your gmail account. Here is link for that: https://developers.google.com/workspace/guides/create-credentials

Here is also the .net reference guide too: https://developers.google.com/gmail/api/quickstart/dotnet

mathis1337
  • 1,426
  • 8
  • 13
  • I'm upvoting the answer because it provides a method to get me to where I am going. The question was asked to find out how the library was meant to be used. I've written a lot of libraries that perform some kind of data manipulation, and I have never written one that provides its own containers for data but expects the user to use a third party class so that they can use mine. The Google API library has those classes there for a reason. While there are methods of *not* using them, I was curious as to how they should be used. I am still curious, and would love to have my question reopened. – CodeWarrior Aug 20 '22 at 03:10