我正在使用 Gmail API ,基本上我想连接到我的GMail帐户来阅读我的电子邮件,INBOX类别,并获取每封邮件的基本信息(标题/主题,从,到,日期和发件人。)
我正在尝试根据自己的需要调整 this Google样本(用C#编写),我正在寻找C#或Vb.Net的解决方案,无论如何。
(请注意,Google会针对不同的用户所示国家/地区显示不同的代码示例,因此该网页的代码可能与每个网站的代码不同,而Google的逻辑确实非常糟糕。)
我在下面的代码中遇到的问题是:
lblInbox.MessagesTotal
属性中获得了空值。msgItem.Raw
属性也总是空的。这是我尝试过的,请注意,在调整Google示例时,我认为"user"
参数应该是Gmail用户帐户名称("MyEmail@GMail.com"
),但我不确定应该那样。
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
我会要求最重要的需求(但是,非常欢迎任何帮助解决其他提到的问题):
这是我现在正在使用的代码,目的是检索指定邮箱标签的所有Message
的集合,问题是{{ 1}}和Payload
Body
对象的成员为空,因此我无法阅读该电子邮件。
我做错了什么?。
newMsg
答案 0 :(得分:22)
目前由于某种原因,许多属性都会从任何请求中返回null
。如果我们有一个电子邮件ID列表,我们仍然可以解决这个问题。然后,我们可以使用这些电子邮件ID发送另一个请求以检索更多详细信息:from
,date
,subject
和body
。 @DalmTo也在正确的轨道上,但由于最近更改了标题,因此标题不够近,这需要更多请求。
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 unread emails...
// 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;
}
}
目前,此方法将检索所有电子邮件ID,并为每个电子邮件ID获取每封电子邮件的subject
,from
,date
和body
。整个方法都有评论。如果您有不明白的地方,请告诉我。另一方面,在将此作为答案发布之前再次进行了测试。
答案 1 :(得分:9)
有人问代码,这是完成的测试代码。他们中的大多数是从Zaggler复制的,但我最终会遇到一些例外情况。所以我追溯到上述问题。
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;
}
}
}
}
答案 2 :(得分:2)
GoogleWebAuthorizationBroker.AuthorizeAsync中的用户参数仅供FileDatastore用于存储您的凭据,请查看我的教程Google .net – FileDatastore demystified以获取更多信息。
我的VB.net非常生锈,就像6年生锈一样,但在C#中你可以做这样的事情
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返回可以循环遍历它们的消息对象列表。
Users.Messages包含应包含主题和来往的标题。
我在gmail上也有一个非常古老的C#教程可能有所帮助。
更新以回复您的更新:
删除后会发生什么:
.LabelIds = New Repeatable(Of String)({folder.Id})
labelIds string仅返回标签与所有指定标签ID匹配的消息。
您似乎正在发送文件夹ID。尝试使用user.lables.list返回列出用户邮箱中的所有标签
答案 3 :(得分:2)
首先:向上投票@codexer的回答。
其次,在他的代码中使用以下函数来解码base64URL编码的主体。 Google不仅对base64进行了编码,还对URL进行了编码: - /
/// <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);
}
答案 4 :(得分:1)
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);
我们可以获取包含所有这些消息属性的.eml文件。