从C# Web应用程序发送电子邮件的最佳架构方式是什么?

8

我正在开发一个即将上线的Web应用程序,现在我正在尝试找出处理应用程序发送邮件的最佳方式。我完全理解如何使用MailMessage和SmtpClient类从应用程序发送电子邮件,但我的问题是从不同角度来看待这个问题。在此项目之前,我主要负责支持开发时间更早的旧应用程序。在这些应用程序中,当它们需要发送电子邮件时,他们将所有HTML标签嵌入到C#代码中的实际消息中。

我正在开发的应用程序将有一个电子邮件模板,作为一种样式容器,不同的消息将嵌入到模板的主要内容div中。我想避免在此应用程序中对这些模板进行硬编码,因此我一直在努力找出最佳的项目布局方式。我考虑过使用t4模板,并将不同的t4读入应用程序并应用指定参数的String.Format以添加名称/电子邮件到要发送的消息中。然而,我不确定这是否是最佳方法。

我的另一个想法是为每种类型的消息定义一个类,但这将再次硬编码消息,正如我所说,我不想这样做。

我的问题是,您过去是如何处理这个问题的?什么起作用了,什么没有,原因是什么?我在网上搜索了很多,但要么唯一的内容是如何发送消息,要么我没有使用正确的Google关键词。


到目前为止,您在聊天代码方面自己尝试了什么?这样在线上的某个人就可以看到并可能帮助您。这取决于您真正寻找什么,发送电子邮件并不是一项困难的任务,因为.NET为您提供了许多选项,可以使用System.Net.Mail或通过Web应用程序使用System.Web.Mail,还有很多以前的示例,您可以在此网站上搜索和研究,或者查看codeproject.com上的示例。 - MethodMan
1
主要的代码都只在我脑海中。在我花费大量时间编写代码之前,我想了解最佳方法。我已经尝试研究这个问题数小时了。我不需要关于如何完成的详细指导,只需要知道应该做什么。我提出的想法都在我的问题中,但是正如我所说,我不确定这是否是解决问题的最佳途径。 - tostringtheory
你有数据库访问权限吗?你可以将每种类型的消息、收件人、主题、正文等存储在数据库中,并在其之上构建简单的维护程序。你还可以在电子邮件正文中输入各种标签,作为其他文本(如用户名称)的占位符。我以前做过这个,效果还不错。 - hawkke
该应用程序确实有一个数据库,这是我曾经考虑过的事情之一。一开始我有些犹豫是否应该将消息存储到数据库中,因为我不确定是否应该将消息存储在数据库中,但毫无疑问的是,消息可以随时更新是一个优点。 接收者当前也存储在数据库中。感谢您的建议,我现在会更加认真地考虑它,因为我知道其他人已经很好地完成了它。不过,我仍然想知道是否有更好的方法。 - tostringtheory
2个回答

2
我是这样做的:
  • 按照惯例,使用 ViewModel 和 Razor 模板编写代码。
  • 当创建电子邮件时,使用http://razorengine.codeplex.com/来加载和解析模板。
  • 请注意,如果要在线程中发送电子邮件,则不要使用 Html 和 Url helper,因为它们依赖于 HttpContext,在这种情况下你没有 HttpContext。如有需要,请自行构建您自己的 helper。
例如,如果你在应用程序中有一个 ViewModel Car 用于显示某个信息,你也可以将此 ViewModel 作为 Razor 模板的 @model 在电子邮件中使用。

谢谢提供链接。这确实更接近我所寻找的方式。我猜你是将模板作为一个实际的单独文件,而不是像他们在主页上展示的那样硬编码进去了,我的理解正确吗? - tostringtheory
当然不会有硬编码,对于每个电子邮件,我都有一个cshtml文件。因此,您也可以将其用作应用程序中的电子邮件预览。 - Marc
我曾考虑过这个问题,但对于使用它还是有些犹豫,因为我将从应用程序的服务端而不是网站端发送电子邮件。该网站最终将在Windows Azure上运行,因此我希望尽量减少服务和网站之间传递电子邮件/用户信息以进行发送。这也是将电子邮件存储在数据库中听起来不错的原因之一 - 更新应用程序可能需要很长时间。 - tostringtheory
我永远不会在数据库中执行任何应用程序逻辑,因为那只是存储数据的地方。你应该能够删除数据库并重新开始而不会丢失应用程序代码,否则你会被束缚。但这是程序员开始讨论的一个点 :) 你在哪里打破界限?为什么不把整个应用程序代码加载到数据库中并执行,这样你就可以更轻松地更新它...知道我的意思吗? :) - Marc
重新部署应用程序会影响所有内容吗?还是Azure会进行比较以确定只有cshtml页面发生了更改?谢谢您的建议,我还是一个初级编程工作人员,但我想要好好学习所学,并希望以正确的方式学习。然而,在许多情况下,“正确”的方式可能是主观的,正如您所提到的那样。 - tostringtheory
显示剩余3条评论

0

我曾经在几个场合下需要这样做。最初我使用了基于Rick Strahl博客文章的ASP.Net模板引擎。它能够工作,但总是有一些问题让我很头疼。

后来我转而使用NVelocity模板引擎,并发现这是一种非常简单的创建和维护电子邮件模板的方法。还有许多其他的模板引擎,我猜下一次我可能会认真看看Razor engine

将值合并到模板的代码:

private string Merge(ManualTypeEnum manualType, Object mergeValues)
{
    var body = "";
    var templateFile = string.Format("{0}MailTemplate.vm", manualType);
    var velocity = new VelocityEngine();
    var props = new ExtendedProperties();
    props.AddProperty("file.resource.loader.path", Config.EmailTemplatePath);
    velocity.Init(props);
    var template = velocity.GetTemplate(templateFile);
    var context = new VelocityContext();
    context.Put("Change", mergeValues);
    using (var writer = new StringWriter())
    {
        template.Merge(context, writer);
        body = writer.ToString();
    }
    return body;
}

要合并的值作为匿名对象传递,可以包括各种类型,包括列表等,例如:

var emailBody = Merge(newDocument.ManualType, new
{
    ManualType = newDocument.ManualType.ToString(),
    Message = change.Message,
    NewTitle = newDocument.Title ?? "",
    NewVersion = newDocument.Version ?? "",
    Contact = From,
    Changes = change.ToList(),
});

嗯...看起来我可以用文件来做这件事,但是我可能会考虑将Razor引擎与数据库结合起来,从数据行中获取信息,然后进行转换。关于关注点分离呢?你觉得这样做会混淆它们吗? - tostringtheory
重点在于上下文。当我接手这个应用程序时,使用上面的代码的应用程序已经过时且不堪重负,对于发送的电子邮件的数量/复杂性来说,使用数据库存储模板将是过度设计。考虑到模板只是一个字符串,那么您可以将该字符串存储在文件或数据库中,具体取决于您的应用程序。使用Razor模板的好处之一是Visual Studio支持,因此您将获得语法着色等功能。如果您将它们存储在数据库中,则每当您想要修改它们时,都会添加几个额外的步骤,即提取、更改、更新。 - David Clarke
非常正确。然而在我的情况下,将其存储在数据库中可能会更容易些。当然我可以在我的电脑上拥有文件,并在需要时通过代码更新数据库。部署更改到Azure花费很长时间,因此我会犹豫是否要为这样的小更改重新部署。 - tostringtheory

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接