我想使用 WinForms 技术开发一个用C#或Vb.Net编写的非常简单的应用程序,它将帮助我自动执行一项简单的任务,包括访问我的 Outlook .com 帐户阅读从 Youtube 收到的电子邮件,然后提取视频网址。
我的网络相关知识并不好,我陷入了最重要的一点,试图找到最简单的方法来完成这项任务(我的意思是.Net或第三方API的官方Microsoft API或其他方式可以做到此操作,尝试应用所需的 OAuth2 自动关联来访问电子邮件帐户。
我知道下面的代码并没有集中在正确的方向上,因为缺乏授权,但我不知道如何实现它既不是如何阅读电子邮件,所以这就是我试过的:
string url = "https://outlook.office.com/api/v2.0/me/messages";
string result = "";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "GET";
try {
using (WebClient wc = new WebClient()) {
wc.Encoding = Encoding.UTF8;
result = wc.DownloadString(url);
}
} catch (Exception ex) {
MessageBox.Show(ex.Message);
}
如何访问我的 Outlook.com 帐户以阅读我拥有的收件箱电子邮件的标题和内容?另外,但也可选择回复(只有在可能的情况下,并没有太多问题),我如何删除电子邮件?。
请注意,此问题仅适用于 Outlook.com 在线服务,而不是 Outlook 的桌面客户端,而不是 COM 库的使用或 Office365 。
我知道我没有人要求帮助并提出一些必要条件,所有的帮助对我都很感激,但这次我需要特别要求,因为我的头脑疯狂试图理解,使用并且适应从头开始制作的 OAuth2 解决方案,它生成了很长的代码,我根本不理解,这对我来说太过分了。
出于这个原因,只有当提供的解决方案基于使用第三个pary库来促进所有这些任务时,我才会接受这个问题的答案,因为它将作为 OAuth2的完整抽象。 实施,例如 RestSharp , CodeScales 或 DotNetOpenAuth ,或其他任何一项(免费)lib将为我处理所需的东西,而不是需要自己从头开发 OAuth2 算法。
我的调查开始阅读 this 微软的Outlook开发。页面,关注 this 邮件API参考, this REST API文档, this Outlook。 com API, this 一种入门文章,以 this 结尾使用ASP.Net作为完全说明性示例。
我从微软的文章中清楚地看到的只是......没有什么,我注册了应用程序并创建了客户端ID和秘密,但微软没有为 Winforms <提供任何示例/ strong>所以我试图将他们的官方 ASP.NET 示例翻译成 WinForms 但没有成功。
在浪费时间之后,我找到了 this OAuth 文档页面,其中提供了一些.NET,我想这将有助于OAuth2授权,然后我发现 DotNetOpenAuth 库似乎非常完整,我还使用 DotNetOpenAuth 找到了Outlook的 this 代码示例但同样是 ASP.NET ,还有 these 通用和官方 DotNetOpenAuth 的代码示例,但我不能找到任何可以帮助我做我想做的事情。
答案 0 :(得分:2)
一般的想法是遵循这里的教程:Get Started with Mail, Calendar, and Contacts REST APIs但我会尝试简化它并使用Winforms示例演示它。
首先,您需要创建应用程序注册门户并将其注册到应用程序注册门户(当然,对于给定的应用程序,您只需执行一次):
现在,在您的“任何设备”代码(包括winforms)中,您需要进行身份验证。最简单的方法是使用ADAL(“Active Directory身份验证库”)。源代码在此处https://github.com/AzureAD/azure-activedirectory-library-for-dotnet可用,二进制文件可用作nuget。
不幸的是,今天你可以在nuget上获得的最新版本命名为 Microsoft.IdentityModel.Clients.ActiveDirectory 对我不起作用(它有一个我在这里报告的错误https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/issues/412已经修复了,但现在服务器抱怨某些应用程序与服务器不兼容)。
所以你必须使用旧的“实验性的”(记住将来的某一天,我们将不得不切换):Microsoft.Experimental.IdentityModel.Clients.ActiveDirectory
您希望在获取身份验证令牌时确保使用正确的范围。范围在此处定义:Outlook mail, calendar, and contacts scopes并表示许可区域。如果不指定范围,除了进行身份验证之外,您无需执行任何操作。
因此,如果您想阅读邮件,请使用“https://outlook.office.com/mail.read”范围。
当您尝试应用程序时,在身份验证对话框之后,它应该向用户显示同意屏幕(这里我们看到我们要求邮件范围:“阅读邮件”):
一旦身份验证工作,您可以直接使用REST api,这可能不是那么容易,或者是懒惰并使用另一个包:Microsoft.Office365.OutlookServices-V2.0将为您完成所有底层的REST / OData魔术。好消息是这个API非常完整,所以它应该允许你做其他的事情,比如消息创建,删除等。
outlook.com案例有一个重要的注意事项:并非所有帐户都为此整个REST API启用(请查看此处的“REST API可用性”一章:Outlook Mail),因此您可能希望创建一个新的测试。
以下是示例应用的winforms代码,该应用将查询10条消息并将其添加到列表框中。
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Experimental.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Office365.OutlookServices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private const string authority = "https://login.microsoftonline.com/common";
private const string clientId = "blablabl-abla-blab-abla-blablablab"; // TODO: put your application id here
private const string redirectUri = "urn:ietf:wg:oauth:2.0:oob"; // put your redirect uri here (should be the same)
// we cache the token for the duration of this form
// you could/should use the FileCache class provided in the sample here https://dev.outlook.com/restapi/tutorial/dotnet
private TokenCache _cache = new TokenCache();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// since all packages force async,
// we have to avoid threading issues
BeginInvoke((Action)(() => GetMessages()));
}
private async void GetMessages()
{
// use the Microsoft.Experimental.IdentityModel.Clients.ActiveDirectory nuget package for auth
var authContext = new AuthenticationContext(authority, _cache);
var result = await authContext.AcquireTokenAsync(
new[] { "https://outlook.office.com/mail.read" },
null,
clientId,
new Uri(redirectUri),
new PlatformParameters(PromptBehavior.Always, this));
// use the Microsoft.Office365.OutlookServices-V2.0 nuget package from now on
var client = new OutlookServicesClient(new Uri("https://outlook.office.com/api/v2.0"), () => Task.FromResult(result.Token));
var messages = await client.Me.Messages
.Take(10) // get only 10 messages
.ExecuteAsync();
// fill some list box
// (beware, some messages have a null subject)
foreach (var msg in messages.CurrentPage)
{
listBox1.Items.Add(msg.Subject);
}
}
}
}
答案 1 :(得分:0)
我只是想分享(几乎)最终的解决方案,我扩展了@ Simon Mourier 提供的解决方案,以迭代特定文件夹的所有电子邮件,如果是电子邮件来自Youtube,废弃里面的网址,然后收回电子邮件。
什么时候应用?,好吧,只需根据你需要解析电子邮件的情况进行调整,我的情况非常具体,我有大约500个频道订阅,所以我在一个月内从Youtube积累了大约200封电子邮件,大多数电子邮件来自音乐频道,我刚刚阅读了电子邮件以复制网址以使用JDownloader下载它,因此这对于救助者来说非常有用,因为它将为我完成所有任务。
Private Const Authority As String = "https://login.microsoftonline.com/common"
Private Const ClientId As String = "OUR API ID"
' Put your redirect uri here (should be the same).
Private Const RedirectUri As String = "urn:ietf:wg:oauth:2.0:oob"
' We cache the token for the duration of this Form.
' You could/should use the FileCache class provided in the sample here:
' https://dev.outlook.com/restapi/tutorial/dotnet
Private cache As New TokenCache()
Private Sub Form1_Shown() Handles MyBase.Shown
' Since all packages force async, we have to avoid threading issues.
Me.BeginInvoke(Sub() GetMessages())
End Sub
Private Async Sub GetMessages()
' Use the 'Microsoft.Experimental.IdentityModel.Clients.ActiveDirectory' Nuget package for auth.
Dim authContext As New AuthenticationContext(Authority, cache)
Dim result As AuthenticationResult =
Await authContext.AcquireTokenAsync({"https://outlook.office.com/mail.readwrite"},
Nothing, ClientId, New Uri(RedirectUri),
New PlatformParameters(PromptBehavior.Auto, Me))
' Use the 'Microsoft.Office365.OutlookServices-V2.0' Nuget package from now on.
Dim client As New OutlookServicesClient(New Uri("https://outlook.office.com/api/v2.0"),
Function() Task.FromResult(result.Token))
' I have a rule set to automatically move all emails received from Youtube to a folder with name "Youtube".
Dim folder As IMailFolder =
Await client.[Me].MailFolders.Where(Function(f As IMailFolder) f.DisplayName = "Youtube").ExecuteSingleAsync()
Dim messages As IPagedCollection(Of IMessage) =
Await client.[Me].MailFolders.GetById(folder.Id).Messages.ExecuteAsync()
Do While True
Me.ParseYoutubeMessages(messages.CurrentPage)
If messages.MorePagesAvailable Then
messages = Await messages.GetNextPageAsync
Else
Exit Do
End If
Loop
End Sub
Private Async Sub ParseYoutubeMessages(ByVal messageList As IReadOnlyList(Of IMessage))
Dim urlRegex As New Regex("""http://www.youtube.com/.+watch.+uploademail""", RegexOptions.IgnoreCase)
For Each msg As IMessage In messageList
If (msg.From.EmailAddress.Name.Equals("YouTube", StringComparison.OrdinalIgnoreCase)) Then
Dim body As String = msg.Body.Content
Dim isMatch As Boolean = urlRegex.IsMatch(body)
If Not (isMatch) Then
Throw New InvalidOperationException("Youtube url regex doesn't match.")
Else
Dim urlMatches As MatchCollection = urlRegex.Matches(body)
Dim urls As String() =
(From m As Match In urlMatches.Cast(Of Match)
Select Environment.NewLine & m.Value).Distinct().ToArray()
File.AppendAllText("C:\Youtube Urls.txt", String.Join("", urls))
msg.IsRead = True
Await msg.MoveAsync("DeletedItems")
End If
End If
Next msg
End Sub
答案 2 :(得分:0)
在2018年进行了更新-Microsoft Graph API现在可以控制授予对365世界中对象(包括电子邮件)的访问权限。请参见此链接以获取4个步骤的概述:https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_user