Comment récupérer mes messages Gmail à l’aide de l’API Gmail?

Ce que je veux réaliser:


J’utilise l’ API Gmail et j’aimerais me connecter à mon compte GMail pour lire mes courriels, dans la catégorie INBOX, et obtenir des informations de base sur chaque message (titre / sujet, de , à , à , date et l’expéditeur).

Problèmes:


J’essaie d’adapter cet exemple Google, écrit en C #, à mes propres besoins. Je cherche une solution en C # ou Vb.Net, peu importe.

(Sachez que Google montre différents exemples de code pour différents pays d’utilisateurs. Le code de cette page Web ne sera peut-être pas le même pour tous, la logique de Google est vraiment nul.)

Les problèmes que j’ai avec le code ci-dessous sont les suivants:

  • Je reçois une valeur vide dans la propriété lblInbox.MessagesTotal .
  • msgItem.Raw propriété msgItem.Raw est toujours vide aussi.
  • Je n’ai pas encore découvert comment parsingr uniquement les messages qui se trouvent dans la catégorie INBOX.
  • Je n’ai pas encore découvert comment déterminer si un message est lu ou non lu.
  • Je n’ai pas encore découvert comment déterminer les informations de base d’un message (sujet, de, à, date, expéditeur).

C’est ce que j’ai essayé. Notez que lors de l’adaptation de l’exemple de Google, j’imaginais que "user" argument "user" devrait être le nom du compte utilisateur Gmail ( "[email protected]" ), mais je ne suis pas sûr que cela devrait être le cas. .

 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 

Question:


Je demanderai le besoin le plus important (toutefois, toute aide pour résoudre les autres problèmes mentionnés est la bienvenue):

  • En C # ou VB.Net, comment puis-je obtenir une collection pour parcourir tous les courriels appartenant au groupe Boîte de réception?.

Mettre à jour:

C’est le code que j’utilise actuellement, l’intention est de récupérer une collection de tous les Message de l’ étiquette de boîte aux lettres spécifiée, le problème est que le membre Payload and Body de l’object newMsg est null, je ne peux donc pas le lire. le courriel.

Qu’est-ce que je fais mal?

 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 Ssortingng)({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 Ssortingng.IsNullOrEmpty(msgsResponse.NextPageToken) Then msgsRequest.PageToken = msgsResponse.NextPageToken msgsResponse = Await msgsRequest.ExecuteAsync() Else Exit Do End If Loop Return messages End If End Function 

Actuellement, pour une raison ou une autre, la plupart des propriétés reviennent null à la demande. Nous pouvons toujours contourner cela si nous avons une liste des identifiants de messagerie. Nous pouvons ensuite utiliser ces identifiants de courrier électronique et envoyer une autre demande pour récupérer des détails supplémentaires: de, date, sujet et corps. @DalmTo était également sur la bonne voie, mais pas assez près des en-têtes, car il a été modifié récemment, ce qui nécessitera quelques demandes supplémentaires.

 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().ToSsortingng()) ); } var gmailService = new GmailService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = this.GetType().ToSsortingng() }); 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) { Ssortingng from = ""; Ssortingng date = ""; Ssortingng subject = ""; Ssortingng 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 Ssortingng codedBody = body.Replace("-", "+"); codedBody = codedBody.Replace("_", "/"); byte[] data = Convert.FromBase64Ssortingng(codedBody); body = Encoding.UTF8.GetSsortingng(data); //now you have the data you want.... } } } } } }catch (Exception){ MessageBox.Show("Failed to get messages!", "Failed Messages!", MessageBoxButtons.OK); } } static Ssortingng getNestedParts(IList part, ssortingng curr) { ssortingng 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; } } 

Actuellement, cette méthode récupère tous les identifiants de courrier électronique et, pour chaque identifiant de courrier électronique, obtient l’ subject , la date et le body de chaque courrier. Il y a des commentaires tout au long de la méthode, s’il y a quelque chose que vous ne comprenez pas, s’il vous plaît faites le moi savoir. Sur une autre note: cela a été testé à nouveau avant de poster cela comme une réponse .

désolé ce n’est pas une réponse, je ne peux pas append de commentaire à la réponse de Zaggler (qui vient juste de rejoindre), alors postez-la comme nouvelle réponse, la réponse de Zaggler est très bonne, mais il y a un petit problème. lorsque le corps de l’e-mail comporte plus d’une partie. Convert.FromBase64 ….. ne fonctionne pas sur deux chaînes base64 jointes. donc une exception se produira. mieux convertir puis rejoint les parties du corps.

Quelqu’un demande le code, et voici le code testé terminé. la plupart d’entre eux sont copiés à partir de Zaggler, mais avec quelques exceptions. Je suis donc descendu au problème décrit ci-dessus.

 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 ssortingng[] Scopes = { GmailService.Scope.GmailModify }; static ssortingng ApplicationName = "Gmail API .NET Quickstart"; static void Main(ssortingng[] args) { UserCredential credential; using (var stream = new FileStream("client_secret.json", FileMode.Open, FileAccess.Read)) { ssortingng 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) { Ssortingng from = ""; Ssortingng date = ""; Ssortingng subject = ""; Ssortingng 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 = DecodeBase64Ssortingng(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 Ssortingng DecodeBase64Ssortingng(ssortingng s) { var ts = s.Replace("-", "+"); ts = ts.Replace("_", "/"); var bc = Convert.FromBase64Ssortingng(ts); var tts = Encoding.UTF8.GetSsortingng(bc); return tts; } static Ssortingng GetNestedBodyParts(IList part, ssortingng curr) { ssortingng 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 = DecodeBase64Ssortingng(parts.Body.Data); str += ts; } } else { return GetNestedBodyParts(parts.Parts, str); } } return str; } } } } 

Premièrement: réponse du vote positif @codexer.

Deuxièmement, utilisez la fonction suivante dans son code pour décoder le corps codé base64URL. Non seulement Google a codé le corps en base64, il est également codé en URL: – /

 ///  /// Turn a URL encoded base64 encoded ssortingng into readable UTF-8 ssortingng. ///  /// base64 URL ENCODED ssortingng. /// UTF-8 formatted ssortingng private ssortingng DecodeURLEncodedBase64EncodedSsortingng(ssortingng sInput) { ssortingng sBase46codedBody = sInput.Replace("-", "+").Replace("_", "/").Replace("=", Ssortingng.Empty); //get rid of URL encoding, and pull any current padding off. ssortingng sPaddedBase46codedBody = sBase46codedBody.PadRight(sBase46codedBody.Length + (4 - sBase46codedBody.Length % 4) % 4, '='); //re-pad the ssortingng so it is correct length. byte[] data = Convert.FromBase64Ssortingng(sPaddedBase46codedBody); return Encoding.UTF8.GetSsortingng(data); } 

Le paramètre utilisateur de GoogleWebAuthorizationBroker.AuthorizeAsync est simplement utilisé par FileDatastore pour stocker vos informations d’identification. Consultez mon tutoriel Google .net – FileDatastore démystifié pour plus d’informations.

Mon VB.net est très rouillé comme 6 ans rouillé mais en C # vous pourriez faire quelque chose comme ça

 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 retourne une liste d’objects de message que vous pouvez faire suivre en boucle.

Users.Messages contient un en-tête qui devrait avoir le sujet et le / vers.

J’ai aussi un très vieux didacticiel C # sur gmail qui pourrait aider.

Mettre à jour pour répondre à votre mise à jour:

Que se passe-t-il lorsque vous supprimez:

 .LabelIds = New Repeatable(Of Ssortingng)({folder.Id}) 

labelIds ssortingng Renvoie uniquement les messages dont les étiquettes correspondent à tous les ID d’étiquette spécifiés.

Il semble que vous envoyiez un identifiant de dossier. essayez d’utiliser user.lables.list qui retourne Listes de toutes les étiquettes de la boîte aux lettres de l’utilisateur

 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(); ssortingng converted = msg.Raw.Replace('-', '+'); converted = converted.Replace('_', '/'); byte[] decodedByte = Convert.FromBase64Ssortingng(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); 

Nous pouvons obtenir le fichier .eml avec toutes les propriétés de message comme ceci.