.NET 个人博客-发送邮件优化🧐

个人博客-发送邮件优化🧐

前言

之前的发送邮件就弄了个方法,比如回复评论会给评论的人发送邮件,留言回复也是,而且2者的代码有很多一样的地方,比较冗余。然后也是抽空优化一下,思路也是比较常用的工厂+策略模式,然后评论回复和留言回复的模板是不一样的,所以需要创建模板类和方法。。。

内容比较多,可以自己创建个小项目试试~

模板创建

⌨先把模板给定义好

定义EmailContent

主要是用传入发送邮件的内容,Content参数为必须,其他的可以根据自己的需求进行更改。

public class EmailContent
{
    public string Content { get; set; }
    public string? Link { get; set; }
}

public class EmailContent<T>
{
    public string Content { get; set; }
    public string Link { get; set; }
    public T Data { get; set; }
}

首先创建一个基类定义邮件内容生成的方法:

  • EmailTemplate:基本模板类
  • SEmailTemplate:泛型模板类
public abstract class EmailTemplateBase
{
    protected abstract string GetStyle();
}

public abstract class EmailTemplate:EmailTemplateBase
{
    public string GenerateContent(EmailContent emailContent)
    {
        return $"<html>\n<head>\n<style>{GetStyle()}</style>\n</head>\n<body>\n{GetBodyContent(emailContent)}\n</body>\n</html>";
    }
    protected abstract string GetBodyContent(EmailContent emailContent);
}

public abstract class SEmailTemplate<T>:EmailTemplateBase
{
    public string GenerateContent(EmailContent<T> emailContent)
    {
        return $"<html>\n<head>\n{GetStyle()}\n</head>\n<body>\n{GetBodyContent(emailContent)}\n</body>\n</html>";
    }
    
    protected abstract string GetBodyContent(EmailContent<T> emailContent);
}

然后为每一种邮件内容创建一个子类:

情况一:简单情况

只发送简单的邮件内容,不包含对象等复杂内容。

  • GetStyle 里面写样式就行
  • GetBodyContent 里面写内容
public class MessageBoardNotificationEmailTemplate:EmailTemplate
{
    protected override string GetStyle()
    {
        return @"
            /* 添加样式 */
            body {
                font-family: Arial, sans-serif;
                font-size: 14px;
                line-height: 1.5;
                color: #333;
            }
            .box {
                background-color:#90F8FF ;
                border-radius: 5px;
                padding: 20px;
            }
            h1 {
                font-size: 24px;
                font-weight: bold;
                margin-bottom: 20px;
                color: #333;
            }
            p {
                margin-bottom: 10px;
                color: #333;
            }
            a {
                color: #333;
            }";
    }

    protected override string GetBodyContent(EmailContent emailContent)
    {
        return $@"
            <div class='box'>
                <h1>ZY知识库</h1>
                <h3>留言板通知</h3>
                <p>内容如下:{emailContent.Content}</p>
                <p>点击跳转:<a href='https://pljzy.top/MsgBoard?page=1'>留言板地址</a></p>
            </div>";
    }
}

情况二:复杂情况

  • GetStyle 同上
  • GetBodyContent 里面参数为泛型参数EmailContent<LinkExchange>,这样在发送邮件时就能发送对象信息
public class LinksNotificationEmailTemplate:SEmailTemplate<LinkExchange>
{
    protected override string GetStyle()
    {
        return "";
    }

    protected override string GetBodyContent(EmailContent<LinkExchange> emailContent)
    {
        const string blogLink = "<a href=\"https://pljzy.top\">ZY知识库</a>";
        var sb = new StringBuilder();
        sb.AppendLine($"<p>{emailContent.Content}</p>");
        sb.AppendLine($"<br>");
        sb.AppendLine($"<p>以下是您申请的友链信息:</p>");
        sb.AppendLine($"<p>网站名称:{emailContent.Data.Name}</p>");
        sb.AppendLine($"<p>介绍:{emailContent.Data.Description}</p>");
        sb.AppendLine($"<p>网址:{emailContent.Data.Url}</p>");
        sb.AppendLine($"<p>站长:{emailContent.Data.WebMaster}</p>");
        sb.AppendLine($"<p>补充信息:{emailContent.Data.Reason}</p>");
        sb.AppendLine($"<br>");
        sb.AppendLine($"<br>");
        sb.AppendLine($"<br>");
        sb.AppendLine($"<p>本消息由 {blogLink} 自动发送,无需回复。</p>");
        return sb.ToString();
    }
}

发送邮件服务

首先,创建一个接口定义邮件发送服务

public interface IEmailService
{
    Task SendEmail(string recipient, EmailTemplate template, EmailContent emailContent);
    Task SendEmail<T>(string recipient, SEmailTemplate<T> template,  EmailContent<T> emailContent);
}

然后创建实现类MimeKitEmailService ,这里用的是​MimeKit库生成邮件内容

public class MimeKitEmailService : IEmailService
{
    private readonly SmtpClient client;

    public MimeKitEmailService(SmtpClient client)
    {
        this.client = client;
    }

    public async Task SendEmail(string recipient, EmailTemplate template, EmailContent emailContent)
    {
        var message = CreateEmailMessage(recipient, template.GenerateContent(emailContent));
        await SendAsync(message);
    }

    public async Task SendEmail<T>(string recipient, SEmailTemplate<T> template, EmailContent<T> emailContent)
    {
        var message = CreateEmailMessage(recipient, template.GenerateContent(emailContent));
        await SendAsync(message);
    }

    private MimeMessage CreateEmailMessage(string recipient, string content)
    {
        var message = new MimeMessage();
        message.From.Add(new MailboxAddress("ZY", "zy1767992919@163.com"));
        message.To.Add(new MailboxAddress("", recipient));
        message.Subject = "来自ZY知识库通知~";
        message.Body = new TextPart("html")
        {
            Text = content
        };

        return message;
    }

    private async Task SendAsync(MimeMessage message)
    {
        await client.SendAsync(message);
        await client.DisconnectAsync(true);
    }
}

创建工厂类

配置

将邮箱信息存放在appsettings.json文件中方便统一管理

{
  "Email": {
    "Address": "你的邮箱",
    "Password": "授权码"
  }
}

然后创建一个类对应上述参数

public class EmailConfig
{
    public string Address { get; set; }
    public string Password { get; set; }
}

Program.cs文件中绑定EmailConfig类,添加到容器中

builder.Services.Configure<EmailConfig>(builder.Configuration.GetSection("Email"));

工厂类

创建EmailServiceFactory工厂类用于实例化EmailService

  1. 网易:smtp.163.com
  2. QQ:smtp.qq.com

EmailServiceFactory类中注入IOptions<EmailConfig>来邮箱信息配置

public class EmailServiceFactory
{
    private readonly EmailConfig emailConfig;
    public EmailServiceFactory(IOptions<EmailConfig> emailConfigOptions)
    {
        emailConfig = emailConfigOptions.Value;
    }
    public async Task<IEmailService> CreateEmailService()
    {
        var client = new SmtpClient();
        // configure the client
        await client.ConnectAsync("smtp.163.com", 465, true);
        await client.AuthenticateAsync(emailConfig.Address, emailConfig.Password);

        return new MimeKitEmailService(client);
    }
}

注册EmailServiceFactory服务

builder.Services.AddTransient<EmailServiceFactory>();

发送邮件

声明 IEmailServiceEmailServiceFactory变量,然后使用 emailServiceFactoryCreateEmailService 方法异步创建一个 IEmailService 对象用于创建邮箱通信,并将其赋给 emailService 变量,然后new一个模板对象,最后调用emailServiceSendEmail方法发送邮件

private IEmailService emailService;
private readonly EmailServiceFactory _emailServiceFactory;

public LinkExchangeService(MyDbContext myDbContext,
        EmailServiceFactory emailServiceFactory)
 {
     _myDbContext = myDbContext;
     _emailServiceFactory = emailServiceFactory;
 }

public async Task SendEmailOnAdd(LinkExchange item)
{
    //创建邮箱连接
    emailService = await _emailServiceFactory.CreateEmailService();
    //内容模板
    var template = new LinksNotificationEmailTemplate(); 
    //发送邮件
    await emailService.SendEmail(item.Email, template,
                                 new EmailContent<LinkExchange>()
                                 {
                                     Content = "您好,友链申请已通过!感谢支持,欢迎互访哦~",
                                     Data = item
                                 });
}

参考资料

posted @   妙妙屋(zy)  阅读(196)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
  1. 1 够爱(翻自 曾沛慈) 是我呀卡司宝贝
  2. 2 老人と海 ヨルシカ
  3. 3 生生世世爱 黄霄雲
  4. 4 希望有羽毛和翅膀 imzat
老人と海 - ヨルシカ
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : n-buna

作曲 : n-buna

编曲 : n-buna

靴紐が解けてる 木漏れ日は足を舐む

息を吸う音だけ聞こえてる

貴方は今立ち上がる 古びた椅子の上から

柔らかい麻の匂いがする

遥か遠くへ まだ遠くへ

遥か遠くへ まだ遠くへ

僕らは身体も脱ぎ去って

まだ遠くへ 雲も越えてまだ向こうへ

風に乗って

僕の想像力という重力の向こうへ

まだ遠くへ まだ遠くへ

海の方へ

靴紐が解けてる 蛇みたいに跳ね遊ぶ

靴紐が解けてる 蛇みたいに跳ね遊ぶ

貴方の靴が気になる

僕らは今歩き出す 潮風は肌を舐む

手を引かれるままの道

さぁまだ遠くへ まだ遠くへ

さぁまだ遠くへ まだ遠くへ

僕らはただの風になって

まだ遠くへ 雲も越えてまだ向こうへ

風に乗って 僕ら想像力という縛りを抜け出して

まだ遠くへ まだ遠くへ 海の方へ

靴紐が解けてる 僕はついにしゃがみ込む

靴紐が解けてる 僕はついにしゃがみ込む

鳥の鳴く声だけ聞こえてる

肩をそっと叩かれてようやく僕は気が付く

海がもう目の先にある

あぁまだ遠くへ まだ遠くへ

あぁまだ遠くへ まだ遠くへ

僕らは心だけになって

まだ遠くへ 海も越えてまだ向こうへ

風に乗って 僕の想像力という重力の向こうへ

まだ遠くへ まだ遠くへ

海の方へ

僕らは今靴を脱ぐ さざなみは足を舐む

僕らは今靴を脱ぐ さざなみは足を舐む

貴方の眼は遠くを見る

ライオンが戯れるアフリカの砂浜は

海のずっと向こうにある

点击右上角即可分享
微信分享提示