使用 MAPI 发送到 Outlook 2013 是否有我遗漏的特别之处?
Is there something special about Sending to Outlook 2013 with MAPI that I'm missing?
我正在使用 Visual Studio 2008 开发一个简单的 MAPI 接口,用于从应用程序发送电子邮件和附件。与 Thunderbird 和 Outlook 6 配合使用时效果很好,但 Outlook 2013 给我带来了各种各样的痛苦。
有两个关键问题:
1) 电子邮件进入 Outlook 的发件箱,但在发送时被退回(或者看起来像我认为这是内部的)并显示消息 "None of your e-mail accounts could send to this recipient."
- 如果我在 Outlook 中使用那个确切的电子邮件地址撰写新邮件,它就可以正常工作。我已经尝试了两个不同的出站 SMTP 帐户,我知道它们都可以工作,并且可以手动工作,但是对于 IMAP,它们被卡住了。我使用的 IMAP 代码没有发起者数据,我已经破解了它以尝试使其工作(我发布的代码有点原始,因为我仍在尝试解决这个问题)
2) Outlook 将显示 "A program is trying to send an e-mail message on your behalf".
- 我已按照大量联机帮助中的说明将 Outlook 信任中心访问权限设置为 "Never warn about activity",但问题仍然存在。我不禁觉得这些可能是相关的?
我想知道 Outlook 2013 是否需要比我提供的更多的数据,或者我是否在做一些自相矛盾的假设。
注意:这些测试是在三台不同的机器上进行的 - Thunderbird 在我的主要 Win 10 开发机器上,Outlook 6 在 XP 虚拟机上,Outlook 2013 在另一台 Windows 10 机器上。
代码注意事项:我使用 CPtrArrays 来存储调用函数传递的数据。您将在设置收件人时看到 GetAt()。
谢谢!
MapiRecipDesc sender[1];
MapiRecipDesc recipient[50];
MapiFileDesc fileDesc[20];
sender[0].ulRecipClass = MAPI_ORIG;
sender[0].lpszAddress = "me@me.net";
sender[0].lpszName = "Me";
sender[0].lpEntryID = 0;
sender[0].ulEIDSize = 0;
sender[0].ulReserved = 0;
iToCount = 0;
iIndex = 0;
while (iIndex < m_paTo.GetCount()) {
recipient[iToCount].ulRecipClass = MAPI_TO;
recipient[iToCount].lpszAddress = (char *) m_paTo.GetAt(iToCount);
recipient[iToCount].lpszName = (char *) m_paTo.GetAt(iToCount);
recipient[iToCount].lpEntryID = 0;
recipient[iToCount].ulEIDSize = 0;
recipient[iToCount].ulReserved = 0;
iIndex++;
iToCount++;
}
iIndex = 0;
while (iIndex < m_paCC.GetCount()) {
recipient[iToCount].ulRecipClass = MAPI_CC;
recipient[iToCount].lpszAddress = (char *) m_paCC.GetAt(iIndex);
recipient[iToCount].lpszName = (char *) m_paCC.GetAt(iIndex);
recipient[iToCount].lpEntryID = 0;
recipient[iToCount].ulEIDSize = 0;
recipient[iToCount].ulReserved = 0;
iIndex++;
iToCount++;
}
iIndex = 0;
while (iIndex < m_paBCC.GetCount()) {
recipient[iToCount].ulRecipClass = MAPI_BCC;
recipient[iToCount].lpszAddress = (char *) m_paBCC.GetAt(iIndex);
recipient[iToCount].lpszName = (char *) m_paBCC.GetAt(iIndex);
recipient[iToCount].lpEntryID = 0;
recipient[iToCount].ulEIDSize = 0;
recipient[iToCount].ulReserved = 0;
iIndex++;
iToCount++;
}
iFileCount = 0;
iIndex = 0;
while (iIndex < m_paAttachments.GetCount()) {
fileDesc[iFileCount].flFlags = 0;
fileDesc[iFileCount].lpFileType = 0;
fileDesc[iFileCount].lpszFileName = (char *) m_paAttachments.GetAt(iIndex);
fileDesc[iFileCount].lpszPathName = (char *) m_paAttachments.GetAt(iIndex);
fileDesc[iFileCount].nPosition = -1;
fileDesc[iFileCount].ulReserved = 0;
iIndex++;
iFileCount++;
}
TCHAR szSubject[_MAX_PATH];
TCHAR szMessage[5001];
::StrCpy(szSubject, m_sSubject);
::StrCpy(szMessage, m_sMessage);
MapiMessage message;
::ZeroMemory(&message, sizeof(message));
message.lpszSubject = szSubject;
message.nRecipCount = iToCount;
message.lpRecips = recipient;
message.nFileCount = iFileCount;
message.lpFiles = fileDesc;
message.lpszNoteText = szMessage;
message.flFlags = MAPI_SENT | MAPI_UNREAD;
message.lpszConversationID = "123";
message.lpOriginator = sender;
//int nError = SendMail(0, (ULONG_PTR)hWndParent, &message, MAPI_LOGON_UI|MAPI_DIALOG, 0);
int nError = SendMail(0, (ULONG_PTR)hWndParent, &message, MAPI_LOGON_UI, 0);
if (nError != SUCCESS_SUCCESS &&
nError != MAPI_USER_ABORT &&
nError != MAPI_E_LOGIN_FAILURE) {
CString sMessage;
CString sTest = recipient[0].lpszAddress;
sMessage.Format("MapiMail:: SendMail Error code %d Recip count %d: first Recip: %s", nError, message.nRecipCount, sTest);
AfxMessageBox(sMessage);
lLog.WriteString(sMessage);
return false;
}
根据 Barmak Shemirani 的建议,我发布了我自己的答案。如果其他人正在寻找此信息,也许我可以通过将其发布在一个地方来节省他们一些时间。
"None of your e-mail accounts could send to this recipient." 问题可以通过将收件人的电子邮件地址放在名称尖括号中来解决 =42=]收件人结构中的字段。将地址字段留空。所以,例如
::StrCpy(szTo, "<address@email.com>");
recipient[iToCount].ulRecipClass = MAPI_TO;
recipient[iToCount].lpszAddress = 0;
recipient[iToCount].lpszName = szTo;
recipient[iToCount].lpEntryID = 0;
recipient[iToCount].ulEIDSize = 0;
recipient[iToCount].ulReserved = 0;
我已经使用 Outlook 2013 和 2016 以及 Outlook 6、Thunderbird 和 EM Client 对此进行了测试,他们都对此感到满意。显然你也可以输入名称PersonName <name@email.com>
,但我还没有测试过。
Outlook显示问题:
A program is trying to send an e-mail message on your behalf
是软件配置问题。大多数网站建议使用信任中心来设置编程访问以允许其他应用程序通过 MAPI 进行访问。您必须 运行 以管理员身份设置此程序,但 您还必须 运行 以管理员身份设置 Outlook 才能正常工作
解决方法是编辑注册表并在以下位置添加值为 2 的 DWORD PromptSimpleMAPISend:
Computer\HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\x.0\Outlook\Security
奖励答案。如果有人想知道 MAPI 中的 HTML,它不受支持。 MAPI 显然早于 HTML 电子邮件的常见用法。
有一个解决方法。您可以将邮件正文留空,而是将邮件放在 html 文件中,并将该文件作为 MAPI 邮件中的第一个附件。我用 .html
扩展名命名我的文件。
这有点侥幸 - 电子邮件客户端接收它并在电子邮件正文中显示 HTML。您的 html 文件仍将是一个附件,后跟任何其他附件。
我已经使用 Thunderbird、Outlook 和 EM Client 进行了测试。我快速浏览了一封网络电子邮件 reader,它没有显示 html 文本(尽管附件可供阅读)。
我正在使用 Visual Studio 2008 开发一个简单的 MAPI 接口,用于从应用程序发送电子邮件和附件。与 Thunderbird 和 Outlook 6 配合使用时效果很好,但 Outlook 2013 给我带来了各种各样的痛苦。
有两个关键问题:
1) 电子邮件进入 Outlook 的发件箱,但在发送时被退回(或者看起来像我认为这是内部的)并显示消息 "None of your e-mail accounts could send to this recipient."
- 如果我在 Outlook 中使用那个确切的电子邮件地址撰写新邮件,它就可以正常工作。我已经尝试了两个不同的出站 SMTP 帐户,我知道它们都可以工作,并且可以手动工作,但是对于 IMAP,它们被卡住了。我使用的 IMAP 代码没有发起者数据,我已经破解了它以尝试使其工作(我发布的代码有点原始,因为我仍在尝试解决这个问题)
2) Outlook 将显示 "A program is trying to send an e-mail message on your behalf".
- 我已按照大量联机帮助中的说明将 Outlook 信任中心访问权限设置为 "Never warn about activity",但问题仍然存在。我不禁觉得这些可能是相关的?
我想知道 Outlook 2013 是否需要比我提供的更多的数据,或者我是否在做一些自相矛盾的假设。
注意:这些测试是在三台不同的机器上进行的 - Thunderbird 在我的主要 Win 10 开发机器上,Outlook 6 在 XP 虚拟机上,Outlook 2013 在另一台 Windows 10 机器上。
代码注意事项:我使用 CPtrArrays 来存储调用函数传递的数据。您将在设置收件人时看到 GetAt()。
谢谢!
MapiRecipDesc sender[1];
MapiRecipDesc recipient[50];
MapiFileDesc fileDesc[20];
sender[0].ulRecipClass = MAPI_ORIG;
sender[0].lpszAddress = "me@me.net";
sender[0].lpszName = "Me";
sender[0].lpEntryID = 0;
sender[0].ulEIDSize = 0;
sender[0].ulReserved = 0;
iToCount = 0;
iIndex = 0;
while (iIndex < m_paTo.GetCount()) {
recipient[iToCount].ulRecipClass = MAPI_TO;
recipient[iToCount].lpszAddress = (char *) m_paTo.GetAt(iToCount);
recipient[iToCount].lpszName = (char *) m_paTo.GetAt(iToCount);
recipient[iToCount].lpEntryID = 0;
recipient[iToCount].ulEIDSize = 0;
recipient[iToCount].ulReserved = 0;
iIndex++;
iToCount++;
}
iIndex = 0;
while (iIndex < m_paCC.GetCount()) {
recipient[iToCount].ulRecipClass = MAPI_CC;
recipient[iToCount].lpszAddress = (char *) m_paCC.GetAt(iIndex);
recipient[iToCount].lpszName = (char *) m_paCC.GetAt(iIndex);
recipient[iToCount].lpEntryID = 0;
recipient[iToCount].ulEIDSize = 0;
recipient[iToCount].ulReserved = 0;
iIndex++;
iToCount++;
}
iIndex = 0;
while (iIndex < m_paBCC.GetCount()) {
recipient[iToCount].ulRecipClass = MAPI_BCC;
recipient[iToCount].lpszAddress = (char *) m_paBCC.GetAt(iIndex);
recipient[iToCount].lpszName = (char *) m_paBCC.GetAt(iIndex);
recipient[iToCount].lpEntryID = 0;
recipient[iToCount].ulEIDSize = 0;
recipient[iToCount].ulReserved = 0;
iIndex++;
iToCount++;
}
iFileCount = 0;
iIndex = 0;
while (iIndex < m_paAttachments.GetCount()) {
fileDesc[iFileCount].flFlags = 0;
fileDesc[iFileCount].lpFileType = 0;
fileDesc[iFileCount].lpszFileName = (char *) m_paAttachments.GetAt(iIndex);
fileDesc[iFileCount].lpszPathName = (char *) m_paAttachments.GetAt(iIndex);
fileDesc[iFileCount].nPosition = -1;
fileDesc[iFileCount].ulReserved = 0;
iIndex++;
iFileCount++;
}
TCHAR szSubject[_MAX_PATH];
TCHAR szMessage[5001];
::StrCpy(szSubject, m_sSubject);
::StrCpy(szMessage, m_sMessage);
MapiMessage message;
::ZeroMemory(&message, sizeof(message));
message.lpszSubject = szSubject;
message.nRecipCount = iToCount;
message.lpRecips = recipient;
message.nFileCount = iFileCount;
message.lpFiles = fileDesc;
message.lpszNoteText = szMessage;
message.flFlags = MAPI_SENT | MAPI_UNREAD;
message.lpszConversationID = "123";
message.lpOriginator = sender;
//int nError = SendMail(0, (ULONG_PTR)hWndParent, &message, MAPI_LOGON_UI|MAPI_DIALOG, 0);
int nError = SendMail(0, (ULONG_PTR)hWndParent, &message, MAPI_LOGON_UI, 0);
if (nError != SUCCESS_SUCCESS &&
nError != MAPI_USER_ABORT &&
nError != MAPI_E_LOGIN_FAILURE) {
CString sMessage;
CString sTest = recipient[0].lpszAddress;
sMessage.Format("MapiMail:: SendMail Error code %d Recip count %d: first Recip: %s", nError, message.nRecipCount, sTest);
AfxMessageBox(sMessage);
lLog.WriteString(sMessage);
return false;
}
根据 Barmak Shemirani 的建议,我发布了我自己的答案。如果其他人正在寻找此信息,也许我可以通过将其发布在一个地方来节省他们一些时间。
"None of your e-mail accounts could send to this recipient." 问题可以通过将收件人的电子邮件地址放在名称尖括号中来解决 =42=]收件人结构中的字段。将地址字段留空。所以,例如
::StrCpy(szTo, "<address@email.com>"); recipient[iToCount].ulRecipClass = MAPI_TO; recipient[iToCount].lpszAddress = 0; recipient[iToCount].lpszName = szTo; recipient[iToCount].lpEntryID = 0; recipient[iToCount].ulEIDSize = 0; recipient[iToCount].ulReserved = 0;
我已经使用 Outlook 2013 和 2016 以及 Outlook 6、Thunderbird 和 EM Client 对此进行了测试,他们都对此感到满意。显然你也可以输入名称
PersonName <name@email.com>
,但我还没有测试过。Outlook显示问题:
A program is trying to send an e-mail message on your behalf
是软件配置问题。大多数网站建议使用信任中心来设置编程访问以允许其他应用程序通过 MAPI 进行访问。您必须 运行 以管理员身份设置此程序,但 您还必须 运行 以管理员身份设置 Outlook 才能正常工作
解决方法是编辑注册表并在以下位置添加值为 2 的 DWORD PromptSimpleMAPISend:
Computer\HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\x.0\Outlook\Security
奖励答案。如果有人想知道 MAPI 中的 HTML,它不受支持。 MAPI 显然早于 HTML 电子邮件的常见用法。
有一个解决方法。您可以将邮件正文留空,而是将邮件放在 html 文件中,并将该文件作为 MAPI 邮件中的第一个附件。我用
.html
扩展名命名我的文件。这有点侥幸 - 电子邮件客户端接收它并在电子邮件正文中显示 HTML。您的 html 文件仍将是一个附件,后跟任何其他附件。
我已经使用 Thunderbird、Outlook 和 EM Client 进行了测试。我快速浏览了一封网络电子邮件 reader,它没有显示 html 文本(尽管附件可供阅读)。