使用 MailKit 和 Gmail OAuth 发送邮件

2024-01-10

我正在尝试创建一个应用程序,在客户购买时向他们发送电子邮件。我们有自己的 GMail 帐户,我将用它来发送电子邮件。

我已经设置了我的应用程序并在 Google API 控制台中创建了凭据。我发现这个问题 https://github.com/jstedfast/MailKit/issues/606在 MailKit 的 GitHub 上,看起来这是一个足够简单的方法,但它似乎对我不起作用。

这是我的代码:

var secrets = new ClientSecrets
{
    ClientId = [CLIENTID]
    ClientSecret = [SECRET]
};

var googleCredentials = await GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, new[] { GmailService.Scope.MailGoogleCom }, email, CancellationToken.None);
await googleCredentials.RefreshTokenAsync(CancellationToken.None);

using (var client = new SmtpClient())
{
    client.Connect("smtp.gmail.com", 587);

    var credentials = new NetworkCredential(googleCredentials.UserId, googleCredentials.Token.AccessToken);
    client.Authenticate(credentials);

    await client.SendAsync(message);
    client.Disconnect(true);
}

致电给Authenticate给出以下错误:

MailKit.Security.AuthenticationException : AuthenticationInvalidCredentials:5.7.8 用户名和密码不正确 公认。了解更多信息,请访问 5.7.8https://support.google.com/mail/?p=BadCredentials https://support.google.com/mail/?p=BadCredentialsm3-v6sm3447324wrs.39 - gsmtp

例外情况中的谷歌支持页面基本上只是说要么使用两步验证+应用程序密码,要么启用不太安全的应用程序。这两个我都不想要。为什么在 .NET 中做到这一点如此困难?我之前用 Node 做过这个,非常简单:

var smtp = mailer.createTransport({
    service: "Gmail",
    auth: {
        type: "OAuth2",
        user: process.env.EMAIL,
        clientId: process.env.CLIENT_ID,
        clientSecret: process.env.CLIENT_SECRET,
        refreshToken: process.env.REFRESH_TOKEN
    }
});

请不要说我已经看过了这个答案 https://stackoverflow.com/a/24204968/5392786但我真的不明白如何获得 Google 信任的 X509 证书。据我所知,谷歌的文档中没有与此相关的内容。


解决方案是通过身份验证SaslMechanismOAuth2代替NetworkCredential。我现在有以下有效的方法:

var secrets = new ClientSecrets
{
    ClientId = Environment.GetEnvironmentVariable("GMailClientId"),
    ClientSecret = Environment.GetEnvironmentVariable("GMailClientSecret")
};

var googleCredentials = await GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, new[] { GmailService.Scope.MailGoogleCom }, email, CancellationToken.None);
if (googleCredentials.Token.IsExpired(SystemClock.Default))
{
    await googleCredentials.RefreshTokenAsync(CancellationToken.None);
}

using (var client = new SmtpClient())
{
    client.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls);

    var oauth2 = new SaslMechanismOAuth2(googleCredentials.UserId, googleCredentials.Token.AccessToken);
    client.Authenticate(oauth2);

    await client.SendAsync(message);
    client.Disconnect(true);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 MailKit 和 Gmail OAuth 发送邮件 的相关文章

随机推荐

  • 如何在 Flask-SQLAlchemy 应用程序中执行原始 SQL

    如何在 SQLAlchemy 中执行原始 SQL 我有一个 python Web 应用程序 它在 Flask 上运行 并通过 SQLAlchemy 与数据库连接 我需要一种方法来运行原始 SQL 该查询涉及多个表联接以及内联视图 我试过了
  • 使用其名称作为字符串来调用单独的 Windows 窗体

    我需要能够创建一个按钮 当我单击该按钮时 该按钮可以链接到不同的 Windows 窗体 但是 此按钮是动态生成的 有时可以根据需要链接到不同的表单 例如 我的按钮可以链接到 FormA vb 或 FormB vb 我可以让按钮根据需要创建字
  • zig 创建了一个 C 库,但 C 无法使用

    我可以让 Zig 创建一个 C 库 但是当我尝试从 C 程序中使用所述库时 它无法找到所包含函数的定义 我的图书馆定义 const std import std export fn removeAll name const u8 len u
  • 使用 prerender-spa-plugin 时如何加载 Vuetify?

    当我们在开发模式下运行 Vuetify 应用程序时 使用npm run dev 工作正常 然而 当我们使用prerender spa plugin Vuetify CSS 文件正确加载 但所有 JavaScript 组件都不起作用 即单击按
  • 如何在编辑模式下在 UITableView 中添加额外的单元格?

    您知道在表格进入编辑模式后如何让某些单元格出现在表格视图中吗 就像您编辑联系人时 通讯录 iPhone 应用程序所做的那样 也许我错了 但是在编辑联系人时 看起来像是使用了分组的 UITableView 我试过这个 self tableVi
  • Hg 存储库中的 git 子模块?

    我有一个非常旧的项目 其中直接包含另一个项目的源代码 而不是将其链接为库 回到糟糕的日子 当我将所有内容都保存在 CVS 中时 我将外部代码放在供应商分支上并定期导入 现在我的项目位于 git 中 将外部项目作为子模块包含进来会更有意义 但
  • 如何使用日期选择器在 Angular Material 5.0.0 中选择日期范围?

    我正在使用最新的Angular Material 5 0 0 rc0在我的 Angular 5 应用程序中 我正在尝试选择一个日期范围datepicker提供了 Angular 材料 但我找不到任何相关文档 我所能做的就是选择一个start
  • 最大化 div 的高度,周围元素的高度可变

    我有一个 div 我想在基于 100vh 的父级中最大化其大小 问题是我有两个pdiv 还可以根据窗口的宽度更改其高度 从而导致大小变化 现在 快速但肮脏的解决方案可能只是运行 jQuery 片段来检测父级的大小div and pdiv 并
  • 生成具有 2 个 OU 名称的 CSR

    我必须创建一个生成 CSR 的应用程序 在生成 CSR 时 我们需要填写一些详细信息 例如 CN OU 等 问题是我必须向其发送 CSR 的认证机构需要 2 个 OU 组织单位 名称 我用 google 搜索了很多 但找不到任何使用 ope
  • 如何在 Google Analytics 中跟踪“打开新标签”流量

    我有一个推荐网站 它使用一个网址来访问我的实施了谷歌分析的网站 当用户单击链接时 推荐网站会在同一窗口的新选项卡中打开我的网站 我想为每个推荐网站创建一个配置文件 以便每个配置文件都有自己的有关用户活动和交易转化的报告 我是谷歌分析的新手
  • R - 将 data.frame 转换为多维矩阵

    来自 data frame 的示例 x data frame c 1 1 2 2 3 3 c 1 2 1 2 1 2 c 1 1 1 2 2 2 c 12 14 22 24 34 28 colnames x c Store Dept Yea
  • 将 Google Analytics 添加到 Rails 4.2 应用程序

    我有一个使用 Heroku 部署的 Rails 4 2 应用程序 并且尝试向其中添加 Google Analytics 但是 Google Analytics 没有获取任何会话 有什么建议为什么以及如何解决这个问题吗 CODE app la
  • 在办公室 LAN 上设置 xampp 服务器

    我希望在小型办公室内使用 xampp 设置服务器 我当然会保护 xampp 但为了使我的 web 应用程序可供网络上的其他 4 台电脑使用 我是否只创建一个虚拟主机 有没有办法确保只能在局域网上访问Web应用程序 当前设置包括 4 台计算机
  • OpenGL 旋转

    我正在尝试在 OpenGL 中进行简单的旋转 但一定没有抓住重点 我并不是在寻找具体的修复方法 而是在寻找快速解释或更普遍地解释 OpenGL 旋转的链接 目前我有这样的代码 glPushMatrix glRotatef 90 0 0 0
  • 使用 Hadoop MapRed 排序

    Well 我想知道如何在reduce 任务之后更改简单WordCount 程序的排序顺序 我已经制作了另一个按值排序而不是按键排序的映射 但它仍然按升序排序 有没有一种简单的方法可以做到这一点 更改排序顺序 谢谢 韦洛佐 如果您使用的是旧版
  • Android Work Manager - Work Manager 是否能 100% 确保后台执行完成?

    根据我从文档中读到的内容https developer android com topic libraries architecture workmanager https developer android com topic libra
  • 如何限制pyqt中QLineEdit中的用户输入

    我有一个QLineEdit我想限制QLineEdit仅接受整数 它应该像输入掩码一样工作 但我不想用inputmask 因为如果用户点击QLineEdit光标将位于鼠标单击的位置 用户需要导航到 0 位置并输入他想要的内容 有没有什么替代方
  • 如何在 SQL Server 2012 中设置每周自动备份?

    请建议我如何在 SQL Server 2012 中设置自动数据库备份 我需要对 SQL Server 中的所有数据库 目前仅包含 3 个 进行每周自动备份 该备份在每周五 0100 点 凌晨 1 点 运行 这些备份文件 bak 应放置在 E
  • Swift NSScriptCommand 执行默认实现

    我在 Objective C 中使用了这段代码 implementation KDOrderInfo id performDefaultImplementation NSString theRequest self directParame
  • 使用 MailKit 和 Gmail OAuth 发送邮件

    我正在尝试创建一个应用程序 在客户购买时向他们发送电子邮件 我们有自己的 GMail 帐户 我将用它来发送电子邮件 我已经设置了我的应用程序并在 Google API 控制台中创建了凭据 我发现这个问题 https github com j