以前都使用 System.Net.Mail.SmtpClient 來發送 email,但他被標記為已過時,並且在 .NET Core 中不推薦使用。
本篇就使用在官方說明文件中推薦使用的 jstedfast/MailKit 套件來示範傳送 email
程式碼:
註:寄送者信箱和寄信者名稱不一定會被送信伺服器所接受,部分送信伺服器會以登入的使用者帳號傳送。
ㄜ... Email 並沒有被寄出去,出現下面的錯誤
原因是因為 2022 年 5 月 30 日起不再支援第三方應用程式只使用帳號密碼登入,解決方式是使用應用程式密碼登入。
依照步驟完成兩步驟驗證
回到剛剛的頁面會發現「兩步驟驗證」下面多了一個「應用程式密碼」
點選後在「選擇應用程式」選擇「其他」
輸入完後點選「產生」
將上面的 16 個英文字密碼記錄下來
然後將上面程式碼中原本的密碼替換為這 16 個英文即可。
參考資料:
mimekit.Doc
本篇就使用在官方說明文件中推薦使用的 jstedfast/MailKit 套件來示範傳送 email
安裝套件
先使用 NuGet 安裝 MailKit 套件,或是使用 .NET CLI 執行以下指令安裝
dotnet add package MailKit
程式碼:
string host = "smtp.gmail.com"; // 送信郵件主機
int port = 587; // 送信郵件主機連接埠
string account = "ruyut_mail_server@gmail.com"; // 帳號
string password = "ruyut_mail_server123"; // 密碼
string mailServerName = "Server"; // 寄信者名稱
string mailServerAddress = "ruyut_mail_server@gmail.com"; // 寄送者信箱
string targetAddress = "a@ruyut.com"; // 目標信箱
string subject = "測試信件"; // 信件主旨
string body = "這是一封測試信件"; // 信件內容
MimeMessage message = new();
message.From.Add(new MailboxAddress(mailServerName, mailServerAddress));
message.To.Add(MailboxAddress.Parse(targetAddress));
message.Subject = subject;
message.Body = new TextPart("html")
{
Text = body
};
using SmtpClient client = new();
client.Connect(host, port, false);
client.Authenticate(account, password);
client.Send(message);
client.Disconnect(true);
註:寄送者信箱和寄信者名稱不一定會被送信伺服器所接受,部分送信伺服器會以登入的使用者帳號傳送。
ㄜ... Email 並沒有被寄出去,出現下面的錯誤
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
MailKit.Security.AuthenticationException: 535: 5.7.8 Username and Password not accepted. Learn more at
5.7.8 https://support.google.com/mail/?p=BadCredentials z22-20020aa79596000000b00000000000000000000000000.25 - gsmtp
---> MailKit.Net.Smtp.SmtpCommandException: 5.7.8 Username and Password not accepted. Learn more at
5.7.8 https://support.google.com/mail/?p=BadCredentials z22-20020aa79596000000b00000000000000000000000000.25 - gsmtp
--- End of inner exception stack trace ---
at MailKit.Net.Smtp.SmtpClient.Authenticate(Encoding encoding, ICredentials credentials, CancellationToken cancellationToken)
at MailKit.MailService.Authenticate(Encoding encoding, String userName, String password, CancellationToken cancellationToken)
at MailKit.MailService.Authenticate(String userName, String password, CancellationToken cancellationToken)
at WebApplicationSentEmailTest.Service.MailService.Sent() in C:\Users\ruyut\Documents\RiderProjects\test\2022\WebApplicationSentEmailTest\WebApplicationSentEmailTest\Service\MailService.cs:line 46
at WebApplicationSentEmailTest.Controllers.RuyutController.Sent() in C:\Users\ruyut\Documents\RiderProjects\test\2022\WebApplicationSentEmailTest\WebApplicationSentEmailTest\Controllers\RuyutController.cs:line 20
at Microsoft.Extensions.Internal.ObjectMethodExecutor.<>c__DisplayClass33_0.<WrapVoidMethod>b__0(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.VoidResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
原因是因為 2022 年 5 月 30 日起不再支援第三方應用程式只使用帳號密碼登入,解決方式是使用應用程式密碼登入。
取得 Google 的應用程式密碼
要使用應用程式密碼一定要開啟兩步驟驗證,可以進入 Google 帳戶 點選安全性 > 兩步驟驗證依照步驟完成兩步驟驗證
回到剛剛的頁面會發現「兩步驟驗證」下面多了一個「應用程式密碼」
點選後在「選擇應用程式」選擇「其他」
輸入完後點選「產生」
將上面的 16 個英文字密碼記錄下來
然後將上面程式碼中原本的密碼替換為這 16 個英文即可。
增加附件
string host = "smtp.gmail.com"; // 送信郵件主機
int port = 587; // 送信郵件主機連接埠
string account = "ruyut_mail_server@gmail.com"; // 帳號
string password = "ruyut_mail_server123"; // 密碼
string mailServerName = "Server"; // 寄信者名稱
string mailServerAddress = "ruyut_mail_server@gmail.com"; // 寄送者信箱
string targetAddress = "a@ruyut.com"; // 目標信箱
string subject = "測試信件"; // 信件主旨
string body = "這是一封測試信件"; // 信件內容
MimeMessage message = new();
message.From.Add(new MailboxAddress(mailServerName, mailServerAddress));
message.To.Add(MailboxAddress.Parse(targetAddress));
message.Subject = subject;
BodyBuilder bodyBuilder = new BodyBuilder
{
HtmlBody = body
};
bodyBuilder.Attachments.Add(@"C:\Users\ruyut\Desktop\test.txt");
bodyBuilder.Attachments.Last().ContentDisposition.FileName = "test.txt";
message.Body = bodyBuilder.ToMessageBody();
using SmtpClient client = new();
client.Connect(host, port, false);
client.Authenticate(account, password);
client.Send(message);
client.Disconnect(true);
參考資料:
mimekit.Doc
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com