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).
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:
lblInbox.MessagesTotal
property.msgItem.Raw
property is always empty too.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 ("[email protected]"
), but I'm not sure it should 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},
"[email protected]",
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
I will ask for the most important need (however, any help to solve the other mentioned problems are very welcome):
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
The Gmail API is a RESTful API that can be used to access Gmail mailboxes and send mail. For most web applications the Gmail API is the best choice for authorized access to a user's Gmail data and is suitable for various applications, such as: Read-only mail extraction, indexing, and backup.
sorry this is not an answer, i can't add a comment to Zaggler's answer(just joined), so just post as a new answer, Zaggler's answer is very good, but there is a small problem. when the email body has more then one part. the Convert.FromBase64..... doesn't work on two joined base64 strings. so an exception will be occure. better convert then joined the body parts.
some one ask for the code, and here is the completed tested code. most of them are copied from Zaggler, but i end up with some exceptions. so i traced down to the problem described above.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
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;
namespace GmailTests
{
class Program
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/gmail-dotnet-quickstart.json
static string[] Scopes = { GmailService.Scope.GmailModify };
static string ApplicationName = "Gmail API .NET Quickstart";
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("client_secret.json", FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(
System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/gmail-dotnet-quickstart2.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,
});
var re = service.Users.Messages.List("me");
re.LabelIds = "INBOX";
re.Q = "is:unread"; //only get unread;
var res = re.Execute();
if (res != null && res.Messages != null)
{
Console.WriteLine("there are {0} emails. press any key to continue!", res.Messages.Count);
Console.ReadKey();
foreach (var email in res.Messages)
{
var emailInfoReq = service.Users.Messages.Get("me", email.Id);
var emailInfoResponse = emailInfoReq.Execute();
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 = DecodeBase64String(emailInfoResponse.Payload.Body.Data);
else
body = GetNestedBodyParts(emailInfoResponse.Payload.Parts, "");
//now you have the data you want....
}
}
//Console.Write(body);
Console.WriteLine("{0} -- {1} -- {2}", subject, date, email.Id);
Console.ReadKey();
}
}
}
}
static String DecodeBase64String(string s)
{
var ts = s.Replace("-", "+");
ts = ts.Replace("_", "/");
var bc = Convert.FromBase64String(ts);
var tts = Encoding.UTF8.GetString(bc);
return tts;
}
static String GetNestedBodyParts(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)
{
var ts = DecodeBase64String(parts.Body.Data);
str += ts;
}
}
else
{
return GetNestedBodyParts(parts.Parts, str);
}
}
return str;
}
}
}
}
The user parameter in GoogleWebAuthorizationBroker.AuthorizeAsync is just used by FileDatastore to store your credentials check my tutorial Google .net – FileDatastore demystified for more information.
My VB.net is very rusty like 6 years rusty but in C# you could do something like this
UsersResource.MessagesResource.ListRequest request = service.Users.Messages.List("Users email address");
var response = request.Execute();
foreach (var item in response.Messages) {
Console.WriteLine(item.Payload.Headers);
}
MessageResource.ListRequest returns a list of message objects you can loop though them.
Users.Messages contains header which should have the subject and the to and from.
I also have a really old C# tutorial on gmail that might help.
Update to answer your update:
What happens when you remove:
.LabelIds = New Repeatable(Of String)({folder.Id})
labelIds string Only return messages with labels that match all of the specified label IDs.
It appears you are sending a folder id. try using user.lables.list which returns Lists all labels in the user's mailbox
UsersResource.MessagesResource.GetRequest getReq = null;
Google.Apis.Gmail.v1.Data.Message msg = null;
getReq = gmailServiceObj.Users.Messages.Get(userEmail, MessageID);
getReq.Format = UsersResource.MessagesResource.GetRequest.FormatEnum.Raw;
msg = getReq.Execute();
string converted = msg.Raw.Replace('-', '+');
converted = converted.Replace('_', '/');
byte[] decodedByte = Convert.FromBase64String(converted);
converted = null;
f_Path = Path.Combine(m_CloudParmsObj.m_strDestinationPath,MessageID + ".eml");
if (!Directory.Exists(m_CloudParmsObj.m_strDestinationPath))
Directory.CreateDirectory(m_CloudParmsObj.m_strDestinationPath);
// Create eml file
File.WriteAllBytes(f_Path, decodedByte);
We can get the .eml file with all message properties like this.
First: up-vote @codexer 's answer.
Second, use the following function in his code to decode the base64URL encoded body. Google not only base64 encoded the body, it is also URL encoded :-/
/// <summary>
/// Turn a URL encoded base64 encoded string into readable UTF-8 string.
/// </summary>
/// <param name="sInput">base64 URL ENCODED string.</param>
/// <returns>UTF-8 formatted string</returns>
private string DecodeURLEncodedBase64EncodedString(string sInput)
{
string sBase46codedBody = sInput.Replace("-", "+").Replace("_", "/").Replace("=", String.Empty); //get rid of URL encoding, and pull any current padding off.
string sPaddedBase46codedBody = sBase46codedBody.PadRight(sBase46codedBody.Length + (4 - sBase46codedBody.Length % 4) % 4, '='); //re-pad the string so it is correct length.
byte[] data = Convert.FromBase64String(sPaddedBase46codedBody);
return Encoding.UTF8.GetString(data);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With