ElektroStudios ElektroStudios - 4 months ago 335
Vb.net Question

How to retrieve my Gmail messages using Gmail API?

What I want to acchieve:






I'm using the Gmail API and basically I would like to connect to my GMail account to read my emails, of INBOX category, and get basic info for each message (title/subject, from, to, date, and the sender).

Problems:






I'm trying to adapt this Google sample, written in C#, to my own needs, I'm searching for a solution in C# or Vb.Net, no matter.

( Be aware that Google shows different code examples for different user-countries, so the code of that webpage maybe will not be the same for every one, that Google's logic really sucks. )

The problems I have with the code below, are these:


  • I'm getting an empty value in
    lblInbox.MessagesTotal
    property.

  • msgItem.Raw
    property is always empty too.

  • I didn't yet discovered how to parse only the messages that are inside the INBOX category.

  • I didn't yet discovered how to determine if a message is read or unread.

  • I didn't yet discovered how to determine the basic info of a message (subject, from, to, date, sender).



This is what I've tried, note that when adapting the Google's sample, I assumed that
"user"
argument should be the Gmail user account name (
"MyEmail@GMail.com"
), but I'm not sure if sould be that.

Imports System.Collections.Generic
Imports System.IO
Imports System.Linq
Imports System.Text
Imports System.Threading
Imports System.Threading.Tasks

Imports Google.Apis.Auth.OAuth2
Imports Google.Apis.Services
Imports Google.Apis.Util.Store
Imports Google.Apis.Gmail
Imports Google.Apis.Gmail.v1
Imports Google.Apis.Gmail.v1.Data
Imports Google.Apis.Gmail.v1.UsersResource

Public Class Form1 : Inherits Form

Private Async Sub Test() Handles MyBase.Shown

Await GmailTest()

End Sub

Public Async Function GmailTest() As Task

Dim credential As UserCredential
Using stream As New FileStream("C:\GoogleAPIKey.json", FileMode.Open, FileAccess.Read)
credential = Await GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,
{GmailService.Scope.MailGoogleCom},
"MyEmail@GMail.com",
CancellationToken.None)
End Using

' Create the service.
Dim service As New GmailService(New BaseClientService.Initializer() With {
.HttpClientInitializer = credential,
.ApplicationName = "What I need to put here?"
})

' Get the "INBOX" label/category.
Dim lblReq As UsersResource.LabelsResource.ListRequest = service.Users.Labels.List("me")
Dim lblInbox As Data.Label = lblReq.Execute().Labels.Where(Function(lbl) lbl.Name = "INBOX").Single
Dim msgCount As Integer? = lblInbox.MessagesTotal

MsgBox("Messages Count: " & msgCount)

If (msgCount <> 0) Then

' Define message parameters of request.
Dim msgReq As UsersResource.MessagesResource.ListRequest = service.Users.Messages.List("me")

' List messages of INBOX category.
Dim messages As IList(Of Data.Message) = msgReq.Execute().Messages
Console.WriteLine("Messages:")
If (messages IsNot Nothing) AndAlso (messages.Count > 0) Then
For Each msgItem As Data.Message In messages
MsgBox(msgItem.Raw)
Next
End If

End If

End Function

End Class


Question:






I will ask for the most important need (however, any help to solve the other mentioned problems are very welcome):


  • In C# or Vb.Net, how can I obtain a collection to iterate all the emails that are in the INBOX group?.






Update:



This is the code that I'm using right now, the intention is to retrieve a collection of all
Message
s of the specified mailbox label, the problem is that the
Payload
and
Body
member of
newMsg
object is null, so I can't read the email.

What I'm doing wrong?.

Public Async Function GetMessages(ByVal folder As Global.Google.Apis.Gmail.v1.Data.Label) As Task(Of List(Of Global.Google.Apis.Gmail.v1.Data.Message))

If Not (Me.isAuthorizedB) Then
Throw New InvalidOperationException(Me.authExceptionMessage)

Else
Dim msgsRequest As UsersResource.MessagesResource.ListRequest = Me.client.Users.Messages.List("me")
With msgsRequest
.LabelIds = New Repeatable(Of String)({folder.Id})
.MaxResults = 50
'.Key = "YOUR API KEY"
End With

Dim msgsResponse As ListMessagesResponse = Await msgsRequest.ExecuteAsync()

Dim messages As New List(Of Global.Google.Apis.Gmail.v1.Data.Message)
Do While True

For Each msg As Global.Google.Apis.Gmail.v1.Data.Message In msgsResponse.Messages

Dim msgRequest As UsersResource.MessagesResource.GetRequest = Me.client.Users.Messages.Get("me", msg.Id)
msgRequest.Format = MessagesResource.GetRequest.FormatEnum.Full

Dim newMsg As Message = Await msgRequest.ExecuteAsync()
messages.Add(newMsg)

Next msg

If Not String.IsNullOrEmpty(msgsResponse.NextPageToken) Then
msgsRequest.PageToken = msgsResponse.NextPageToken
msgsResponse = Await msgsRequest.ExecuteAsync()
Else
Exit Do
End If

Loop

Return messages

End If

End Function

Answer

Currently for some reason or another many of the properties are coming back null from any of the request. We can still get around that if we have a list of the email id's. We then can use these email id's and send out another request to retrieve back further details: from, date, subject and body. @Dalm To was on the right track as well, but not close enough about the headers as it has changed recently which will require a few more request.

private async Task getEmails()
        {
            try
            {
                UserCredential credential;
                using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
                {
                    credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                        GoogleClientSecrets.Load(stream).Secrets,
                        // This OAuth 2.0 access scope allows for read-only access to the authenticated 
                        // user's account, but not other types of account access.
                        new[] { GmailService.Scope.GmailReadonly, GmailService.Scope.MailGoogleCom, GmailService.Scope.GmailModify },
                        "NAME OF ACCOUNT NOT EMAIL ADDRESS",
                        CancellationToken.None,
                        new FileDataStore(this.GetType().ToString())
                    );
                }

                var gmailService = new GmailService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = this.GetType().ToString()
                });

                var emailListRequest = gmailService.Users.Messages.List("EMAILADDRESSHERE");
                emailListRequest.LabelIds = "INBOX";
                emailListRequest.IncludeSpamTrash = false;
                //emailListRequest.Q = "is:unread"; //this was added because I only wanted undread email's...

                //get our emails
                var emailListResponse = await emailListRequest.ExecuteAsync();

                if (emailListResponse != null && emailListResponse.Messages != null)
                {
                    //loop through each email and get what fields you want...
                    foreach (var email in emailListResponse.Messages)
                    {

                        var emailInfoRequest = gmailService.Users.Messages.Get("EMAIL ADDRESS HERE", email.Id);
                        //make another request for that email id...
                        var emailInfoResponse = await emailInfoRequest.ExecuteAsync();

                        if (emailInfoResponse != null)
                        {
                            String from = "";
                            String date = "";
                            String subject = "";
                            String body = "";
                            //loop through the headers and get the fields we need...
                            foreach (var mParts in emailInfoResponse.Payload.Headers)
                            {
                                if (mParts.Name == "Date")
                                {
                                    date = mParts.Value; 
                                }else if(mParts.Name == "From" ){
                                    from = mParts.Value;
                                }else if (mParts.Name == "Subject"){
                                    subject = mParts.Value;
                                }

                                if (date != "" && from != "")
                                {
                                    if (emailInfoResponse.Payload.Parts == null && emailInfoResponse.Payload.Body != null)
                                    {
                                        body = emailInfoResponse.Payload.Body.Data;
                                    }
                                    else
                                    {
                                        body = getNestedParts(emailInfoResponse.Payload.Parts, "");
                                    }
                                    //need to replace some characters as the data for the email's body is base64
                                    String codedBody = body.Replace("-", "+");
                                    codedBody = codedBody.Replace("_", "/");
                                    byte[] data = Convert.FromBase64String(codedBody);
                                    body = Encoding.UTF8.GetString(data);


                                    //now you have the data you want....

                                }

                            }
                        }

                    }
                }

            }catch (Exception){
                MessageBox.Show("Failed to get messages!", "Failed Messages!", MessageBoxButtons.OK); 
            }
        }

static String getNestedParts(IList<MessagePart> part, string curr)
        {
            string str = curr;
            if (part == null)
            {

                return str;
            }else{
                foreach (var parts in part)
                {
                    if (parts.Parts  == null)
                    {
                        if (parts.Body != null && parts.Body.Data != null)
                        {
                            str += parts.Body.Data;
                        }
                    }
                    else{
                        return getNestedParts(parts.Parts, str);
                    }
                }

                return str;
            }

        }

Currently this method will retrieve all email id's and for each email id get the subject,from, date and body of each email. There are comments through-out the method, if there is something you do not understand, please let me know. On another note: this was tested again before posting this as an answer.