无法从某些邮件中获取 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"。对于这些情况,消息的完整信息将直接出现在有效负载对象中,不会使用部件属性。
这是一个有一些例子的问题:
我正在创建一个将邮件导入应用程序的 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"。对于这些情况,消息的完整信息将直接出现在有效负载对象中,不会使用部件属性。
这是一个有一些例子的问题: