【问题标题】:Can I read messages from gmail using gmail api and c#?我可以使用 gmail api 和 c# 读取来自 gmail 的消息吗?
【发布时间】:2015-04-16 03:42:14
【问题描述】:


我想使用 c# 和 gmail api 阅读我的 gmail 帐户中的所有消息。
我可以这样做吗?
我在Gmail API看了很多文章,但是看不到消息。
我还想阅读正文或标题。
如果有人可以帮助我,我会很高兴:)

我用这个代码sn-p:

public static List<Message> ListMessages(GmailService service, String userId)
    {
        List<Message> result = new List<Message>();
        UsersResource.MessagesResource.ListRequest request = service.Users.Messages.List(userId);

        do
        {
            try
            {
                ListMessagesResponse response = request.Execute();
                result.AddRange(response.Messages);
                request.PageToken = response.NextPageToken;
            }
            catch (Exception e)
            {
                Console.WriteLine("An error occurred: " + e.Message);
            }
        } while (!String.IsNullOrEmpty(request.PageToken));

        return result;
    }

还有这个:

foreach (var item in ListMessages(service,"me"))
                MessageBox.Show(item.Snippet);

但结果我的消息框是空的。

【问题讨论】:

    标签: c# gmail gmail-api


    【解决方案1】:

    对我有用

     var inboxlistRequest = service.Users.Messages.List("your-email-address");
     inboxlistRequest.LabelIds = "INBOX";
     inboxlistRequest.IncludeSpamTrash = false;
     //get our emails   
     var emailListResponse = inboxlistRequest.Execute();
     foreach (var mail in emailListResponse.Messages)
     {
           var mailId = mail.Id;
           var threadId = mail.ThreadId;
    
           Message message = service.Users.Messages.Get("your-email-address", mailId).Execute();
           Console.WriteLine(message.Snippet);
     }
    

    【讨论】:

      【解决方案2】:

      是的,按照您说的做应该没有问题。我建议多阅读文档。

      首先您必须进行身份验证 - 下面显示了如何使用服务帐户执行此操作(更多详细信息请点击此处https://developers.google.com/gmail/api/auth/web-server

                          serviceAccountEmail = primaryLink.serviceEmailAddress;
                          certificate = new X509Certificate2(AppDomain.CurrentDomain.BaseDirectory + "certs//" + primaryLink.certificate, primaryLink.certificatePassword, X509KeyStorageFlags.Exportable);
      
                          try
                          {
                              credential = new ServiceAccountCredential(
                              new ServiceAccountCredential.Initializer(serviceAccountEmail)
                              {
                                  User = z.us.emailAccount,
                                  Scopes = new[] { "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "https://mail.google.com/" }
                              }.FromCertificate(certificate));
      
                              if (credential.RequestAccessTokenAsync(CancellationToken.None).Result)
                              {
                                  gs = new GmailService(
                                  new Google.Apis.Services.BaseClientService.Initializer()
                                  {
                                      ApplicationName = "Example",
                                      HttpClientInitializer = credential
                                  });
                              }
                              else
                              {
                                  throw new Exception("gmail authentication Error.");
                              }
                          }
                          catch (Exception ex)
                          {
                              throw ex;
                          }
                          ListMessagesResponse respM = reqM.Execute();
                          if (respM.Messages != null)
                          {   
                               foreach (Message m in respM.Messages)
                               {}
                          } 
      

      获得消息列表后,您可以遍历消息并使用 MIME 解析器或遍历消息结构以获取标题、正文等。

      在这个论坛上有很多帖子介绍了如何做到这一点。

      【讨论】:

      • 得到这个 {"Error:\"unauthorized_client\", Description:\"Unauthorized client or scope in request.\", Uri:\"\""} 错误。电子邮件地址是普通电子邮件地址吗?服务帐户是否必须具有域用户权限?或者代码示例适用于任何常规电子邮件地址?
      • 是的,这是一个用户电子邮件地址。服务帐户的权限需要包括对该用户的访问权限。您不必使用服务帐户 - 您可以让每个用户进行身份验证并获取令牌等以进行访问。您应该查看 Google 示例。
      • 仅使用用户名和密码似乎无法下载联系人/电子邮件。我正在使用这个控制台应用程序,用户不会提供任何输入。所以我想服务帐户是做到这一点的唯一方法。我确实从开发者控制台设置了查看者/所有者权限,但似乎存在错误。
      • 您不使用用户/密码您使用 OAuth 2 身份验证 - 阅读详细信息developers.google.com/gmail/api/auth/about-auth
      • 是的,这是使用 oAuth 完成的,但是在第一条评论中提到了这个错误。我最后的回复是对建议用户名/密码的评论。顺便问一下,您知道服务帐户是否可以与任何常规 gmail 帐户一起使用,还是必须是域帐户?因为对于常规 gmail 帐户,无法登录域管理员,因此无法分配权限。我已经从开发者控制台分配了权限。但错误依然存在。
      【解决方案3】:

      我搜索了一个完整的示例,但没有运气,但这是我的工作示例。基于https://developers.google.com/gmail/api/guides

      1. 认证:https://developers.google.com/gmail/api/auth/web-server
      2. 获取所有封电子邮件
      3. 按 ID 遍历所有电子邮件,并请求消息等。

      这里是获取第一封电子邮件附件的代码 sn-p,但您可以简单地遍历所有 foundIds 以获取所有电子邮件,并使用 message.sn-p 得到身体:

                  List<string> foundIds = new List<string>();
                  string outputDir = "/EXAMPLE/EXAMPLE/"; // your preferred Dir to save attachments to
      
      
      
                  List<Google.Apis.Gmail.v1.Data.Thread> resultThread = new List<Google.Apis.Gmail.v1.Data.Thread>();
                  UsersResource.ThreadsResource.ListRequest requestThread = service.Users.Threads.List("me");
      
      
                  do
                  {
                      try
                      {
                          ListThreadsResponse responseThread = requestThread.Execute();
                          resultThread.AddRange(responseThread.Threads);
      
                          foreach (var item in responseThread.Threads )
                          {
                              foundIds.Add(item.Id);
                          }
      
                          requestThread.PageToken = responseThread.NextPageToken;
                      }
                      catch (Exception e)
                      {
                          Console.WriteLine("An error occurred: " + e.Message);
                      }
                  } while (!String.IsNullOrEmpty(requestThread.PageToken));
      
                  try
                  {
                      Message message = service.Users.Messages.Get("me", foundIds[0]).Execute();
                      IList<MessagePart> parts = message.Payload.Parts;
                      foreach (MessagePart part in parts)
                      {
                          if (!String.IsNullOrEmpty(part.Filename))
                          {
                              String attId = part.Body.AttachmentId;
                              MessagePartBody attachPart = service.Users.Messages.Attachments.Get("me", foundIds[0], attId).Execute();
      
                              // Converting from RFC 4648 base64 to base64url encoding
                              // see http://en.wikipedia.org/wiki/Base64#Implementations_and_history
                              String attachData = attachPart.Data.Replace('-', '+');
                              attachData = attachData.Replace('_', '/');
      
                              byte[] data = Convert.FromBase64String(attachData);
                              File.WriteAllBytes(Path.Combine(outputDir, part.Filename), data);
                          }
                      }
                  }
                  catch (Exception e)
                  {
                      Console.WriteLine("An error occurred: " + e.Message);
                  }
      

      【讨论】:

        【解决方案4】:

        我建议看一下这篇文章,了解如何处理实际的响应结构。 Gmail API 将结果返回给您的方式可能有点复杂。

        https://sigparser.com/developers/email-parsing/gmail-api/

        【讨论】:

          【解决方案5】:

          @BlackCat,您的 ListMessages 看起来不错。现在,要获取消息正文,您必须解码 MimeType "text/plain" 或 "text/html"。例如:

          public static void GetBody(GmailService service, String userId, String messageId, String outputDir)
              {
                  try
                  {
                      Message message = service.Users.Messages.Get(userId, messageId).Execute();
                      Console.WriteLine(message.InternalDate);
                      if (message.Payload.MimeType == "text/plain")
                      {
                          byte[] data = FromBase64ForUrlString(message.Payload.Body.Data);
                          string decodedString = Encoding.UTF8.GetString(data);
                          Console.WriteLine(decodedString);
                      }
                      else
                      {
                          IList<MessagePart> parts = message.Payload.Parts;
                          if (parts != null && parts.Count > 0)
                          {
                              foreach (MessagePart part in parts)
                              {
                                  if (part.MimeType == "text/html")
                                  {
                                      byte[] data = FromBase64ForUrlString(part.Body.Data);
                                      string decodedString = Encoding.UTF8.GetString(data);
                                      Console.WriteLine(decodedString);
                                  }
                              }
                          }
                      }
                      Console.WriteLine("----");
                  }
                  catch (Exception e)
                  {
                      Console.WriteLine("An error occurred: " + e.Message);
                  }
              }
          

          【讨论】:

          • MessagePart 可以包含具有正文部分的其他部分...最简单的方法是使用递归
          猜你喜欢
          • 2015-03-13
          • 2016-12-08
          • 2016-03-18
          • 2014-08-19
          • 2019-06-06
          • 2017-09-18
          • 1970-01-01
          • 2016-10-24
          • 1970-01-01
          相关资源
          最近更新 更多