C# cơ bản .NET Core

Gửi Mail trong .Net Core

Thư viện .NET cung cấp lớp SmtpClient cho phép bạn gửi Email thông qua giao thức SMTP (Simple Mail Transfer Protocol), chức năng của SmtpClient là chuyển Email tới máy chủ SMTP để máy chủ này thực hiện việc chuyển Email đến địa chỉ người nhận.

Khi đã có đối tượng SmtpClient thì thực hiện chuyển email bằng cách biên tập nội dung email với đối tượng lớp MailMessage sau đó gọi phương thức SendMailAsync của SmtpClient để chuyển.

Ví dụ phương thức tính sau để gửi email từ đối tượng SmtpClient đã có

using System;
using System.Net;
using System.Net.Mail;
using System.Threading.Tasks;

namespace MailUtils {
    public static class MailUtils {

    /// <summary>
    /// Gửi Email
    /// </summary>
    /// <param name="_from">Địa chỉ email gửi</param>
    /// <param name="_to">Địa chỉ email nhận</param>
    /// <param name="_subject">Chủ đề của email</param>
    /// <param name="_body">Nội dung (hỗ trợ HTML) của email</param>
    /// <param name="client">SmtpClient - kết nối smtp để chuyển thư</param>
    /// <returns>Task</returns>
    public static async Task<bool> SendMail(string _from, string _to, string _subject, string _body, SmtpClient client) {
            // Tạo nội dung Email
            MailMessage message = new MailMessage (
                from: _from,
                to: _to,
                subject: _subject,
                body: _body
            );
            message.BodyEncoding = System.Text.Encoding.UTF8;
            message.SubjectEncoding = System.Text.Encoding.UTF8;
            message.IsBodyHtml = true;
            message.ReplyToList.Add (new MailAddress (_from));
            message.Sender = new MailAddress (_from);


            try {
                await client.SendMailAsync (message);
                return true;
            } catch (Exception ex) {
                Console.WriteLine (ex.Message);
                return false;
            }
        }

    }
}

Lớp tĩnh trên cung cấp phương thức để bạn gửi mail khi đã có SmtpClient, gọi bằng cách:

await MailUtils.SendMail(_from, _to, _subject, _body, client);

Ví dụ:

await MailUtils.SendMail("myemail@domain.com", "yourmail@domain.com",
                          "Gửi mail", "Nội dung Email", client);

Chú ý lời gọi SendMail trên là bất đồng bộ, nếu code gọi đồng bộ thì: MailUtils.SendMail(..).Wait();

Gửi Mail với Smtp Server Localhost

Nếu bạn có Server Smtp cài đặt cùng host của ứng dụng thì bạn có thể khởi tạo SmtpCLient sau đó sử dụng hàm SendMail ở trên để chuyển thư

Ví dụ, xây dựng phương thức tĩnh SendMailLocalSmtp như sau:

namespace MailUtils {

    public static class MailUtils {
        
        // ...

        /// <summary>
        /// Gửi Email sử dụng máy chủ SMTP cài đặt localhost
        /// </summary>
        public static async Task<bool> SendMailLocalSmtp ( string _from, string _to, string _subject, string _body)
        {
            using (SmtpClient client = new SmtpClient ("localhost")) {
                return await SendMail(_from, _to, _subject, _body, client);
            }
        }

    }
}

Ví dụ thực hiện gửi mail:

await MailUtils.MailUtils.SendMailLocalSmtp("sender@mail.com", "recevier@mail.com", "Chủ đề", "Nội dung email");

Nếu gọi đồng bộ thì:

MailUtils.MailUtils.SendMailLocalSmtp("sender@mail.com", "recevier@mail.com", "Chủ đề", "Nội dung email").Wait();

Gửi Mail bằng cách sử dụng Gmail

Gmail có địa chỉ server SMTP tại: smtp.gmail.com bạn có thể tạo ra SmtpClient kết nối đến Server này để gửi mail, thông tin để kết nối cần cung cấp bao gồm

  • Server SMTP: smtp.gmail.com
  • Cổng kết nối: 587
  • Ssl: phải kích hoạt
  • Xác thực: Phải xác thực kết nối bằng cách cung cấp tài khoản (địa chỉ email google) và password

Thực hiện tạo SmtpClient như sau:

// Tạo SmtpClient kết nối đến smtp.gmail.com
using (SmtpClient client = new SmtpClient ("smtp.gmail.com")) {
    client.Port = 587;
    // Tạo xác thực bằng địa chỉ gmail và password
    client.Credentials = new NetworkCredential (_gmailsend, _gmailpassword);
    client.EnableSsl = true;

    ... sử dụng client để gửi mail tại đây
}

Từ đây xây dựng thêm phương thức SendMailGoogleSmtp như sau:

namespace MailUtils {
    public static class MailUtils {

        public static async Task<bool> SendMail(string _from ....
        public static async Task<bool> SendMailLocalSmtp ( string _from ...
        
        
        /// <summary>
        /// Gửi email sử dụng máy chủ SMTP Google (smtp.gmail.com)
        /// </summary>
        public static async Task<bool> SendMailGoogleSmtp (string _from, string _to, string _subject, 
                                                            string _body, string _gmailsend, string _gmailpassword) {

            MailMessage message = new MailMessage (
                from: _from,
                to: _to,
                subject: _subject,
                body: _body
            );
            message.BodyEncoding = System.Text.Encoding.UTF8;
            message.SubjectEncoding = System.Text.Encoding.UTF8;
            message.IsBodyHtml = true;
            message.ReplyToList.Add (new MailAddress (_from));
            message.Sender = new MailAddress (_from);

            // Tạo SmtpClient kết nối đến smtp.gmail.com
            using (SmtpClient client = new SmtpClient ("smtp.gmail.com")) {
                client.Port = 587;
                client.Credentials = new NetworkCredential (_gmailsend, _gmailpassword);
                client.EnableSsl = true;
                return await SendMail(_from, _to, _subject, _body, client);
            }

        }
    }
}

Như vậy để gửi mail sử dụng Gmail bạn chỉ việc thực hiện:

await MailUtils.MailUtils.SendMailGoogleSmtp("mailgui@mail.com", "mailnhan@mail.com", "Chủ đề", "Nội dung",
                                              "yourgmail@gmail.com", "yourgmailpassword");

Hoặc gọi đồng bộ

MailUtils.MailUtils.SendMailGoogleSmtp("mailgui@mail.com", "mailnhan@mail.com", "Chủ đề", "Nội dung",
                                              "yourgmail@gmail.com", "yourgmailpassword").Wait();

LƯU Ý QUAN TRỌNG

Để Gmail cho phép SmtpClient kết nối đến server SMTP của nó với xác thực là tài khoản gmail của bạn, bạn cần thiết lập tài khoản email của bạn như sau:

Vào địa chỉ https://myaccount.google.com/security

Ở menu trái chọn mục Bảo mật, sau đó tại mục Quyền truy cập của ứng dụng kém an toàn phải ở chế độ bật

gmail

Đồng thời tài khoản Gmail cũng cần bật IMAP

Truy cập địa chỉ https://mail.google.com/mail/#settings/fwdandpop

gmail

Mã nguồn App Console gửi Mail: CS030_SendMail

Dùng MailKit gửi Mail trong ASP.NET với Gmail

SmtpClient mặc dù vẫn được dùng nhưng .NET đánh dấu nó lỗi thời về khuyên dùng MailKit (https://github.com/jstedfast/MimeKit). Để tích hợp thư viện MailKit bạn thực hiện các lệnh:

dotnet add package MailKit
dotnet add package MimeKit

Sau đây hướng dẫn để dùng MailKit gửi mail có sử dụng Smtp Server từ Gmail.

Ta sẽ lưu thông tin cấu hình email tại config của ứng dụng:

Lưu cấu hình Email dưới khóa EmailSettings của file appsettings.json, nội dung như sau:

{

  // các mục khác của config

  "MailSettings": {
    "Mail": "gmail của bạn ví dụ: xuanthulab.net@gmail.com",
    "DisplayName": "Tên Hiện Thị (ví dụ XUANTHULAB",
    "Password": "passowrd ở đây",
    "Host": "smtp.gmail.com",
    "Port": 587
  }
}

Các cấu hình này có thể ánh xạ vào thuộc tính của một lớp, hãy áp dụng bài Cấu hình ứng dụng ASP.NET

Xây dựng một lớp là MailSettings có các thuộc tính giống config như sau:

public class MailSettings
{
    public string Mail { get; set; }
    public string DisplayName { get; set; }
    public string Password { get; set; }
    public string Host { get; set; }
    public int Port { get; set; }

}

Sau đó đăng ký vào dịch vụ hệ thống (xem đăng ký options vào dịch vụ) để lớp nào cần dùng MailSettings có thể Inject nó vào. Mở file Startup.cs cập nhật:

public class Startup {

    // Thêm khởi tạo để lấy IConfiguration của ứng dụng
    IConfiguration _configuration;
    public Startup (IConfiguration configuration) {
        _configuration = configuration;
    }

    public void ConfigureServices (IServiceCollection services) {

        // ...

        services.AddOptions ();                                         // Kích hoạt Options
        var mailsettings = _configuration.GetSection ("MailSettings");  // đọc config
        services.Configure<MailSettings> (mailsettings);                // đăng ký để Inject

    }

    // ... các phương thức khác
}

Tạo dịch vụ gửi Mail và đăng ký dịch vụ vào hệ thống

Lớp MailContent để mô tả thông tin email sẽ gửi

// Chứa thông tin Email sẽ gửi (Trường hợp này chưa hỗ trợ đính kém file)
public class MailContent
{
    public string To { get; set; }              // Địa chỉ gửi đến
    public string Subject { get; set; }         // Chủ đề (tiêu đề email)
    public string Body { get; set; }            // Nội dung (hỗ trợ HTML) của email

}

Xây dựng giao diện ISendMailService để triển khai dịch vụ

using System.Threading.Tasks;

public interface ISendMailService {
    Task SendMail(MailContent mailContent);
    
    Task SendEmailAsync(string email, string subject, string htmlMessage);
}

Triển khai ISendMailService thành lớp SendMailService với nội dung như sau

using System;
using System.Threading.Tasks;
using MailKit.Security;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MimeKit;

public class SendMailService : ISendMailService {
    private readonly MailSettings mailSettings;

    private readonly ILogger<SendMailService> logger;


    // mailSetting được Inject qua dịch vụ hệ thống
    // Có inject Logger để xuất log
    public SendMailService (IOptions<MailSettings> _mailSettings, ILogger<SendMailService> _logger) {
        mailSettings = _mailSettings.Value;
        logger = _logger;
        logger.LogInformation("Create SendMailService");
    }

    // Gửi email, theo nội dung trong mailContent
    public async Task SendMail (MailContent mailContent) {
        var email = new MimeMessage ();
        email.Sender = new MailboxAddress(mailSettings.DisplayName, mailSettings.Mail);
        email.From.Add(new MailboxAddress(mailSettings.DisplayName, mailSettings.Mail));
        email.To.Add (MailboxAddress.Parse (mailContent.To));
        email.Subject = mailContent.Subject;


        var builder = new BodyBuilder();
        builder.HtmlBody = mailContent.Body;
        email.Body = builder.ToMessageBody ();

        // dùng SmtpClient của MailKit
        using var smtp = new MailKit.Net.Smtp.SmtpClient();

        try {
            smtp.Connect (mailSettings.Host, mailSettings.Port, SecureSocketOptions.StartTls);
            smtp.Authenticate (mailSettings.Mail, mailSettings.Password);
            await smtp.SendAsync(email);
        }
        catch (Exception ex) {
            // Gửi mail thất bại, nội dung email sẽ lưu vào thư mục mailssave
            System.IO.Directory.CreateDirectory("mailssave");
            var emailsavefile = string.Format(@"mailssave/{0}.eml", Guid.NewGuid());
            await email.WriteToAsync(emailsavefile);

            logger.LogInformation("Lỗi gửi mail, lưu tại - " + emailsavefile);
            logger.LogError(ex.Message);
        }

        smtp.Disconnect (true);

        logger.LogInformation("send mail to " + mailContent.To);

    }
    public async Task SendEmailAsync(string email, string subject, string htmlMessage) {
       await SendMail(new MailContent() {
            To = email,
            Subject = subject,
            Body = htmlMessage
       });
    }
}

Đăng ký SendMailService vào dịch vụ của hệ thống, trong ConfigureServices của Startup.cs thêm vào

// Đăng ký SendMailService với kiểu Transient, mỗi lần gọi dịch
// vụ ISendMailService một đới tượng SendMailService tạo ra (đã inject config)
services.AddTransient<ISendMailService, SendMailService>();

Từ đây bạn có thể Inject ISendMailService vào các Controller hay các PageModel ..., khi đã có ISendMailService chỉ việc gọi ISendMailService.SendMail để gửi

Gửi thử email

Trong ứng dụng ASP.NET Core đơn giản, có thể thực hiện đoạn mã kiểm tra khi truy cập url /testmail

app.UseEndpoints (endpoints => {
    endpoints.MapGet ("/", async context => {
        await context.Response.WriteAsync ("Hello World!");
    });

    endpoints.MapGet("/testmail", async context => {

        // Lấy dịch vụ sendmailservice
        var sendmailservice = context.RequestServices.GetService<ISendMailService>();

        MailContent content = new MailContent {
            To = "xuanthulab.net@gmail.com",
            Subject = "Kiểm tra thử",
            Body = "<p><strong>Xin chào xuanthulab.net</strong></p>"
        };

        await sendmailservice.SendMail(content);
        await context.Response.WriteAsync("Send mail");
    });

});

Mã nguồn ASP_NET_CORE/07.sendmail


Đăng ký nhận bài viết mới