如何从一个LightSwitch应用程序中发送HTML电子邮件
[原文发表地址] How To Send HTML Email from a LightSwitch Application
[原文发表时间] 27 Jan 2011 7:31 AM
不久前,Paul Patterson写了一个非常棒的、逐步实现的博客帖子,它基于一个论坛上的提问,是关于如何使用LightSwitch的System.Net.Mail来自动发送电子邮件。如果你错过了这个帖子,这里有链接:
Microsoft LightSwitch – 从 Light Switch发送电子邮件
如果你想要对发生在服务器端的数据更新管道内的事情发电子邮件以作出回应,这是一个很好的解决方法。在他的例子中,他展示了如何用SMTP服务器来发送一个简单的、基于文本的电子邮件,以对一个正被植入数据库的新的设定作出反应。在这个帖子中,我想要向你展示你可以怎样从数据中来创建更为丰富的HTML邮件并通过SMTP来发送它们。同时我还会提出一个使用Outlook客户来创建电子邮件的客户端解决方案,它允许用户在邮件发送之前查看并修改它。
通过SMTP发送电子邮件
正如Paul解释道,要从LightSwitch middle-tier(服务器端)来发送一封电子邮件你所需要做的就是在Solution Explorer上切换至File View,并且向Server项目添加一个类。 理想情况下你会想要把这个类放进UserCode 文件夹里以保持有序。
提示:如果你没有看到UserCode 这个文件夹那意味着你还没有编写任何服务器规则。要创建这个文件夹你需要返回并在designer中任意选择一个entity,在右上方下拉“Write Code”按钮,并选择一个像entity_Inserted的服务器方法。
发送一封电子邮件的基本代码很简单。你只需要指定SMTP服务器, 用户id, 密码和端口。提示:如果你只知道用户ID和密码,那么你可以尝试使用Outlook 2010来自动为你获取剩余信息。
注意:在我的SMTPMailHelper类中 我在快速地检查是否包含HTML的body参数,如果包含,我会设置合适的邮件属性:
Imports System.Net
Imports System.Net.Mail
Public Class SMTPMailHelper
Const SMTPServer As String = "smtp.mydomain.com"
Const SMTPUserId As String = myemail@mydomain.com
Const SMTPPassword As String = "mypassword"
Const SMTPPort As Integer = 25
Public Shared Sub SendMail(ByVal sendFrom As String,
ByVal sendTo As String,
ByVal subject As String,
ByVal body As String)
Dim fromAddress = New MailAddress(sendFrom)
Dim toAddress = New MailAddress(sendTo)
Dim mail As New MailMessage With mail
.From = fromAddress
.To.Add(toAddress)
.Subject = subject
If body.ToLower.Contains("<html>") Then
.IsBodyHtml = True
End If
.Body = body
End With
Dim smtp As New SmtpClient(SMTPServer, SMTPPort)
smtp.Credentials = New NetworkCredential(SMTPUserId, SMTPPassword)
smtp.Send(mail)
End Sub
End Class
从Entity Data创建HTML
既然我们有了发送邮件的代码,我想要向你展示如何使用Visual Basic的XML 文档来从entity data迅速地生成HTML。(我喜欢XML文档之前也写了许多与之相关的东西)如果你对XML文档还不熟悉,我建议你从这篇文章和这个视频开始。要使用XML文档你需要确保你有一个相关的集合,包括System.Core, System.Xml, 和System.Xml.Linq。
我想要做的是为一个有子Order_Details的Order entity创建一个HTML电子邮件发票。首先,我这么做来使事情简单些:通过点击adding computed properties让 Order_Details 和 Order entities各自计算line item和 order totals,。这些计算属性的代码如下:
Public Class Order_Detail
Private Sub LineTotal_Compute(ByRef result As Decimal)
' Calculate the line item total for each Order_Detail
result = (Me.Quantity * Me.UnitPrice) * (1 - Me.Discount)
End Sub
End Class
Public Class Order
Private Sub OrderTotal_Compute(ByRef result As Decimal)
' Add up all the LineTotals on the Order_Details collection for this Order
result = Aggregate d In Me.Order_Details Into Sum(d.LineTotal)
End Sub
End Class
然后,当订单被输入数据库之后我想发送一封自动的电子邮件。在designer中打开Order entity,并且在右上方下拉“Write Code”按钮,然后选择Order_Inserted来生成该方法的基本框架。要生成HTML你所需要做的是向编辑器中输入良好的XHTML并使用嵌入表达式从entities中拉出数据。
Public Class NorthwindDataService
Private Sub Orders_Inserted(ByVal entity As Order)
Dim toEmail = entity.Customer.Email
If toEmail <> "" Then
Dim fromEmail = entity.Employee.Email
Dim subject = "Thank you for your order!"
Dim body = <html>
<body style="font-family: Arial, Helvetica, sans-serif;">
<p><%= entity.Customer.ContactName %>, thank you for your order!<br></br>
Order date: <%= FormatDateTime(entity.OrderDate, DateFormat.LongDate) %></p>
<table border="1" cellpadding="3"
style="font-family: Arial, Helvetica, sans-serif;">
<tr>
<td><b>Product</b></td>
<td><b>Quantity</b></td>
<td><b>Price</b></td>
<td><b>Discount</b></td>
<td><b>Line Total</b></td>
</tr>
<%= From d In entity.Order_Details
Select <tr>
<td><%= d.Product.ProductName %></td>
<td align="right"><%= d.Quantity %></td>
<td align="right"><%= FormatCurrency(d.UnitPrice, 2) %></td>
<td align="right"><%= FormatPercent(d.Discount, 0) %></td>
<td align="right"><%= FormatCurrency(d.LineTotal, 2) %></td>
</tr>
%>
<tr>
<td></td>
<td></td>
<td></td>
<td align="right"><b>Total:</b></td>
<td align="right"><b><%= FormatCurrency(entity.OrderTotal, 2) %></b></td>
</tr>
</table>
</body>
</html>
SMTPMailHelper.SendMail(fromEmail, toEmail, subject, body.ToString)
End If
End Sub
End Class
诀窍是确保你的HTML像XML(即结构良好的开始/结束标记)然后你可以使用嵌入表达式( <%= 语法)来把Visual Basic代码嵌入HTML。我使用LINQ查询订单细节来填充HTML表格。(顺便说一下,你也可以用我在这展示的其他诀窍来查询HTML)。
因此现在,当一个新的订单进入系统后,一封包含订单细节的、自动生成的HTML电子邮件就被发送至客户。
通过Outlook客户端发送电子邮件
上述的解决方案对于发送自动生成的电子邮件行之有效,但是如果你想要允许用户在邮件发送之前修改邮件呢?在这种情况下我们需要一个可以从LightSwitch 用户界面中被调用解决方案。一个选择是使Microsoft Outlook自动化—很多人似乎使用那种流行的电子邮件客户端,尤其是我的伙伴们)。除此之外,LightSwitch有一个很好的数据网格功能,它允许在完全托管的情况下将这些数据导出到Excel中。我们可以向我们的屏幕添加一个相似的Office办公功能,它会自动地为使用Outlook的用户生成一封电子邮件。这会允许他们在邮件发送前对它进行修改。
这回我们在客户端需要一个helper 类。就像在上述的SMTP例子中一样,通过Solution Explorer 中的file view添加一个新的类,但是这一次选择Client 项目。这个类使用COM自动化,它是Silverlight 4及更高版本的一个功能。首先我们需要通过检查AutomationFactory.IsAvailable的属性来核查Windows机器d 上的浏览器是否脱机运行。然后我们需要获得一个Outlook的引用,如果它没有打开请打开这个应用程序。剩余的代码会创建电子邮件并向用户演示它:
Imports System.Runtime.InteropServices.Automation
Public Class OutlookMailHelper
Const olMailItem As Integer = 0
Const olFormatPlain As Integer = 1
Const olFormatHTML As Integer = 2
Public Shared Sub CreateOutlookEmail(ByVal toAddress As String,
ByVal subject As String,
ByVal body As String)
Try
Dim outlook As Object = Nothing
If AutomationFactory.IsAvailable Then
Try
'Get the reference to the open Outlook App
outlook = AutomationFactory.GetObject("Outlook.Application")
Catch ex As Exception 'If Outlook isn't open, then an error will be thrown.
' Try to open the application
outlook = AutomationFactory.CreateObject("Outlook.Application")
End Try
If outlook IsNot Nothing Then
'Create the email
' Outlook object model (OM) reference:
' https://msdn.microsoft.com/en-us/library/ff870566.aspx
Dim mail = outlook.CreateItem(olMailItem)
With mail
If body.ToLower.Contains("<html>") Then
.BodyFormat = olFormatHTML
.HTMLBody = body
Else
.BodyFormat = olFormatPlain
.Body = body
End If
.Recipients.Add(toAddress)
.Subject = subject
.Save()
.Display()
'.Send()
End With
End If
End If
Catch ex As Exception
Throw New InvalidOperationException("Failed to create email.", ex)
End Try
End Sub
End Class
调用这个的代码几乎和之前的例子完全一样。我们使用XML文档以同样的方式创建HTML。唯一的区别是我们想要从我们的OrderDetail屏幕上的一个命令按钮来调用它。(这里是你可以如何向屏幕里添加一个命令按钮)我们把生成HTML电子邮件的代码添加到命令按钮的Execute方法中。如果AutomationFactory.IsAvailable为False,这时我想要禁用这个按钮,你可以在CanExecute方法里检查它。
这是我们在屏幕里需要的代码:
Private Sub CreateEmail_CanExecute(ByRef result As Boolean)
result = System.Runtime.InteropServices.Automation.AutomationFactory.IsAvailable
End Sub
Private Sub CreateEmail_Execute()
'Create the html email from the Order data on this screen
Dim toAddress = Me.Order.Customer.Email
If toAddress <> "" Then
Dim entity = Me.Order
Dim subject = "Thank you for your order!"
Dim body = <html>
<body style="font-family: Arial, Helvetica, sans-serif;">
<p><%= entity.Customer.ContactName %>, thank you for your order!<br></br>
Order date: <%= FormatDateTime(entity.OrderDate, DateFormat.LongDate) %></p>
<table border="1" cellpadding="3"
style="font-family: Arial, Helvetica, sans-serif;">
<tr>
<td><b>Product</b></td>
<td><b>Quantity</b></td>
<td><b>Price</b></td>
<td><b>Discount</b></td>
<td><b>Line Total</b></td>
</tr>
<%= From d In entity.Order_Details
Select <tr>
<td><%= d.Product.ProductName %></td>
<td align="right"><%= d.Quantity %></td>
<td align="right"><%= FormatCurrency(d.UnitPrice, 2) %></td>
<td align="right"><%= FormatPercent(d.Discount, 0) %></td>
<td align="right"><%= FormatCurrency(d.LineTotal, 2) %></td>
</tr>
%>
<tr>
<td></td>
<td></td>
<td></td>
<td align="right"><b>Total:</b></td>
<td align="right"><b><%= FormatCurrency(entity.OrderTotal, 2) %></b></td>
</tr>
</table>
</body>
</html>
OutlookMailHelper.CreateOutlookEmail(toAddress, subject, body.ToString)
Else
Me.ShowMessageBox("This customer does not have an email address",
"Missing Email Address",
MessageBoxOption.Ok)
End If
End Sub
现在当用户点击命令板上的Create Email按钮,HTML电子邮件就会被生成并且在Outlook 邮件窗口打开,它允许用户在点击发送前进行修改。
我希望我已经提供了几个在LightSwitch应用程序中发送HTML电子邮件的选择。当你想使用SMTP从服务器端发送自动电子邮件时,选取第一个方案。当你想要与安装了Outlook的用户进行交流且LightSwitch是运行在脱离浏览器的情况下,请使用Outlook客户端选择第二个方案。
用得开心!