无法从某些邮件中获取 payload.parts

Unable to get payload.parts from certain mails

我正在创建一个将邮件导入应用程序的 Windows 服务。该服务在 Windows Server 2012 R2 上 运行。该服务应该能够将邮件导入另一个应用程序。它需要导入附件、主题、正文、发件人、收件人、更改标签等。我目前正在测试该服务。它几乎运作良好。

问题

少量邮件丢失数据。当我从 gmails api 请求有关邮件的附加信息时,api 无法获取 payload.parts。 Payloads.parts 为空。

尝试过

由于公司其他部分都依赖邮件,所以我尝试将错误的邮件转发到我自己的gmail帐户。所以我可以调试它们。不幸的是,邮件在转发时似乎并没有失败。

我试过重启服务。它总是在同一封邮件上失败。我能够调试的三种类型的邮件具有 MIME 类型:"plain/text"。不确定这是否有所作为。

编辑:找到一个具有 MIME 类型的:"text/html"

代码

从 gmail 中的标签同步邮件的服务 api

 public async Task<IList<Message>> GetAllMessagesFromGoogleApi()
        {
            try
            {
                _logger.LogInformation("connecting to Gmail Api");
                var service = await _gmailMailFacade.InitializeConnectionAsync();

                _logger.LogInformation("Downloading gmail messages");
                var messages = _gmailMailFacade.GetAllMessagesWithFilter(service);
                if (messages == null)
                {
                    _logger.LogInformation("There were no messages to sync, import cancelled" + Environment.NewLine);
                    return null;
                }

                _logger.LogInformation("Downloading extra data to emails");
                var messageAdditionalData = _gmailMailFacade.GetMessageDataToMessages(messages, service);

                return messageAdditionalData;
            }
            catch (NullReferenceException e)
            {
                _logger.LogError($"Something from gmail api returned null: {e}");
                return null;
            }
            catch (Exception e)
            {
                _logger.LogError($"Unexpected exception in {nameof(GmailApiService)}. Method: {System.Reflection.MethodBase.GetCurrentMethod().Name}| e: {e.Message}");
                throw;
            }
        }

连接到 gmail 从 _gmailMailFacade.InitializeConnectionAsync()

运行
        public readonly string[] _scopes = { GmailService.Scope.GmailModify, GmailService.Scope.GmailLabels};
        private string _applicationName = "applicationName";
        private IOptions<GmailOptions> _options;

        public GmailConnectionUtility(IOptions<GmailOptions> options)
        {
            _options = options ?? throw new ArgumentNullException(nameof(options));
        }

        public async Task<UserCredential> GetUserCredential()
        {

            var credentialPath = Path.Combine(_options.Value.CredentialBasePath, _options.Value.ClientSecretName);
            using (var stream =
                new FileStream(credentialPath, FileMode.Open, FileAccess.Read))
            {
                // The file token.json stores the user's access and refresh tokens, and is created
                // automatically when the authorization flow completes for the first time.
                string credPath = Path.Combine(_options.Value.CredentialBasePath, "token.json");
                var credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                    GoogleClientSecrets.Load(stream).Secrets,
                    _scopes,
                    "user",
                    CancellationToken.None,
                    new FileDataStore(credPath, true));

                Console.WriteLine("Credential file saved to: " + credPath);

                return credential;
            }
        }

        public GmailService NewGMailService(UserCredential credential)
        {
            var service = new GmailService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = credential,
                ApplicationName = _applicationName,
            });


            return service;
        }

此方法从 gmail api 获取电子邮件。 _gmailOptions 包含带有标签 ID 的字符串。 运行 来自 _gmailMailFacade.GetAllMessagesWithFilter(服务)

        public IList<Message> GetEmailsWithLabels(GmailService service)
        {
            var emailByLabel = service.Users.Messages.List("Me");
            emailByLabel.LabelIds = _gmailOptions.LabelSyncFrom;
            emailByLabel.IncludeSpamTrash = false;
            var emailsResponse = emailByLabel.Execute().Messages;
            return emailsResponse;
        }

这些方法从 api

        public IList<Message> GetMailDataToMessages(IList<Message> messages, GmailService service)
        {
            return messages.Select(message => GetMailData(message, service)).ToList();
        }

        private Message GetMailData(Message message, GmailService service)
        {
            var logError = "";

            var debugMessage = message;
            try
            {
                logError = $"Unable to get extra data from gmail in {nameof(GmailApiUtility)}," +
                                 $" method: {System.Reflection.MethodBase.GetCurrentMethod().Name}," +
                                 $" on email with subject: {message?.Raw}";

                var request = service.Users.Messages.Get("me", message?.Id).Execute();

                if (request.Payload.Parts == null)
                {
                    _logger.LogError(logError);
                }

                return request;
            }
            catch (NullReferenceException e)
            {
                _logger.LogWarning($"{logError} Exception: {e}");
                return null;
            }
            catch (Exception e)
            {
                _logger.LogError($"Unexpected exception: {e}");
                throw;
            }
        }

对于具有 payload.parts 属性和信息的电子邮件,该电子邮件的负载 mime 类型必须是 "multipart/*"。这就是为什么当负载 mime 类型为 "text/plain" 或 "text/html" 时,您的 payload.parts 为空。

例如,您可以在激活纯文本选项的情况下从 Gmail UI 发送邮件,这将使邮件负载 mime 类型为 "text/plain"。对于这些情况,消息的完整信息将直接出现在有效负载对象中,不会使用部件属性。

这是一个有一些例子的问题: