Udostępnij za pośrednictwem


How To Send HTML Email from a LightSwitch Application

A while back Paul Patterson wrote an awesome step-by-step blog post based on a forum question on how to send an automated email using System.Net.Mail from LightSwitch. If you missed it here it is:

Microsoft LightSwitch – Send an Email from LightSwitch

This is a great solution if you want to send email in response to some event happening in the data update pipeline on the server side. In his example he shows how to send a simple text-based email using an SMTP server in response to a new appointment being inserted into the database. In this post I want to show you how you can create richer HTML mails from data and send them via SMTP. I also want to present a client-side solution that creates an email using the Outlook client which allows the user to see and modify the email before it is sent.

Sending Email via SMTP

As Paul explained, all you need to do to send an SMTP email from the LightSwitch middle-tier (server side) is switch to File View on the Solution Explorer and add a class to the Server project. Ideally you’ll want to put the class in the UserCode folder to keep things organized.

image

TIP: If you don’t see a UserCode folder that means you haven’t written any server rules yet. To generate this folder just go back and select any entity in the designer, drop down the “Write Code” button on the top right, and select one of the server methods like entity_Inserted.

The basic code to send an email is simple. You just need to specify the SMTP server, user id, password and port. TIP: If you only know the user ID and password then you can try using Outlook 2010 to get the rest of the info for you automatically.

Notice in my SMTPMailHelper class I’m doing a quick check to see whether the body parameter contains HTML and if so, I set the appropriate mail property.

 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

Creating HTML from Entity Data

Now that we have the code to send an email I want to show you how we can quickly generate HTML from entity data using Visual Basic’s XML literals. (I love XML literals and have written about them many times before.) If you are new to XML literals I suggest starting with this article and this video. To use XML literals you need to make sure you have an assembly reference to System.Core, System.Xml, and System.Xml.Linq.

What I want to do is create an HTML email invoice for an Order entity that has children Order_Details. First I’ve made my life simpler by adding computed properties onto the Order_Details and Order entities that calculate line item and order totals respectively. The code for these computed properties is as follows:

 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

Next I want to send an automated email when the Order is inserted into the database. Open the Order entity in the designer and then drop down the “Write Code” button on the top right and select Order_Inserted to generate the method stub. To generate HTML all you need to do is type well formed XHTML into the editor and use embedded expressions to pull the data out of the 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

The trick is to make sure your HTML looks like XML (i.e. well formed begin/end tags) and then you can use embedded expressions (the <%= syntax) to embed Visual Basic code into the HTML. I’m using LINQ to query the order details to populate the rows of the HTML table. (BTW, you can also query HTML with a couple tricks as I show here).

So now when a new order is entered into the system an auto-generated HTML email is sent to the customer with the order details.

image

Sending Email via an Outlook Client

 The above solution works well for sending automated emails but what if you want to allow the user to modify the email before it is sent? In this case we need a solution that can be called from the LightSwitch UI. One option is to automate Microsoft Outlook -- most people seem to use that popular email client, especially my company ;-). Out of the box, LightSwitch has a really nice feature on data grids that lets you to export them to Excel if running in full trust. We can add a similar Office productivity feature to our screen that auto generates an email for the user using Outlook. This will allow them to modify it before it is sent.

We need a helper class on the client this time. Just like in the SMTP example above, add a new class via the Solution Explorer file view but this time select the Client project. This class uses COM automation, a feature of Silverlight 4 and higher. First we need to check if we’re running out-of-browser on a Windows machine by checking the AutomationFactory.IsAvailable property. Next we need to get a reference to Outlook, opening the application if it’s not already open. The rest of the code just creates the email and displays it to the user.

 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

The code to call this is almost identical to the previous example. We use XML literals to create the HTML the same way. The only difference is we want to call this from a command button on our OrderDetail screen. (Here’s how you add a command button to a screen.) In the Execute method for the command button is where we add the code to generate the HTML email. I also want to have the button disabled if AutomationFactory.IsAvailable is False and you check that in the CanExecute method.

Here’s the code we need in the screen:

 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

Now when the user clicks the Create Email button on the ribbon, the HTML email is created and the Outlook mail message window opens allowing the user to make changes before they hit send.

image

I hope I’ve provided a couple options for sending HTML emails in your LightSwitch applications. Select the first option to use SMTP when you want automated emails sent from the server side. Select the second option to use the Outlook client when you want to interact with users that have Outlook installed and LightSwitch is running out-of-browser.

Enjoy!

Comments

  • Anonymous
    January 27, 2011
    Excellent post Beth..tnks!  Your content is always educational and practical.  How about an article about the various ways of incorporating LS data into Word docs (including tables) next!  Content controls, Open/customxml, automation etc..which method is best?

  • Anonymous
    January 27, 2011
    Thanks! I did write a post using Word to generate reports with user-defined templates. Check it out here: blogs.msdn.com/.../using-microsoft-word-to-create-reports-for-lightswitch-or-silverlight.aspx Cheers, -B

  • Anonymous
    January 28, 2011
    Aweosme..tnks beth!

  • Anonymous
    February 02, 2011
    My original thought on seeing this post: "Whats all this about blah, blah just show me the code blah, blah." I was wrong, you showed me a very simple way of doing what took much more code 2 years ago.  I too now love xml literals, as of 10 minutes ago ! Bravo Beth.

  • Anonymous
    February 10, 2011
    Hey Beth, I converted this to C#. However now im getting errors about DomainServices not exisiting in System.ServiceModel.DomainServices How can i correct this?

  • Anonymous
    February 11, 2011
    The comment has been removed

  • Anonymous
    February 14, 2011
    Would it be possible to popup the Outlook address book from code and have the selected item be returned to a field on a Lightswitch form?

  • Anonymous
    February 18, 2011
    Hi Graeme, Yes you probably can using the COM object model, I'd have to dig in and play with it though as I don't know what methods to call off-hand. -B

  • Anonymous
    April 27, 2011
    Quick question on your XML literals.   If any value in my "Body" variable comes back as NULL, the entire "Body" becomes null.  I've experienced this in SQL HTML email procedures too, but I can do a simple ISNULL(FieldName, '') to fix it.  Can you tell me what VB/XML syntax I would use to handle this?

  • Anonymous
    June 07, 2011
    Thanks for your example, Betty, but if I use an Exchange server?

  • Anonymous
    September 04, 2011
    Hi Beth, I'm following your lightswitch blogs, videos, your samples everything is fine. But you are always using VB. :) Should you add C# codes of this blog "How To Send HTML Email from a LightSwitch Application" ? Please can you add C# codes for new videos, and blogs like this. Cheers,

  • Anonymous
    October 25, 2011
    Hi Beth, Great article, thanks :D How do you add multiple mail recipients (Cc) when creating the email.

  • Anonymous
    April 15, 2012
    Hi Beth, can you tell me how to send mails with attachments in LS?

  • Anonymous
    April 28, 2012
    Hi Beth Your blog is awesome n very informative. plz provide C# code also with the blog post.

  • Anonymous
    July 19, 2012
    i am unable to add microsoft.office.interop.outlook reference in class .  i am using c# coding . will you help me in this thing ?

  • Anonymous
    September 17, 2012
    Thank you so much for you videos and blogs on LightSwitch.  As a small business IT Manager is about to embark on writing a new in-house quoting system and inventory system, I'm heavily indebted to you for your great tutorials!

  • Anonymous
    October 15, 2012
    In C#: using System; using System.Linq; using System.IO; using System.IO.IsolatedStorage; using System.Collections.Generic; using Microsoft.LightSwitch; using Microsoft.LightSwitch.Framework.Client; using Microsoft.LightSwitch.Presentation; using Microsoft.LightSwitch.Presentation.Extensions; using System.Runtime.InteropServices.Automation; using System.Text; using System.Windows;        public static void CreateOutlookEmail(string toAddress, string subject, string body)        {            dynamic olMailItem = 0;            dynamic olFormatPlain = 1;            dynamic olFormatHTML = 2;            try            {                dynamic outlook;                if (AutomationFactory.IsAvailable)                {                    try                    {                        // Get the reference to the open Outlook App                        outlook = AutomationFactory.GetObject("Outlook.Application");                    }                    catch                    {                        // If Outlook isn't open, then an error will be thrown.                        //  Try to open the application                        outlook = AutomationFactory.CreateObject("Outlook.Application");                    }                    if (outlook != null)                    {                        // Create the email                        //  Outlook object model (OM) reference:                        //  msdn.microsoft.com/.../ff870566.aspx                        dynamic mail = outlook.CreateItem(olMailItem);                        // With...                        if (body.ToLower().Contains("<html>"))                        {                            mail.BodyFormat = olFormatHTML;                            mail.HTMLBody = body;                        }                        else                        {                            mail.BodyFormat = olFormatPlain;                            mail.Body = body;                        }                        mail.Recipients.Add(toAddress);                        mail.Subject = subject;                        mail.Save();                        mail.Display();                        // mail.Send()                    }                }            }            catch (Exception ex)            {                throw new InvalidOperationException("Failed to create email.", ex);            }        }

  • Anonymous
    December 19, 2012
    Hi Beth! i need help to make this HTML editable from client, it's possible? We are making a CRM tool, and there are some mails to we need to change any information every two months... i would like to make this on the frontside, not in code. thankS!!

  • Anonymous
    December 24, 2012
    Thanks Michael Washington for providing me the mail code in c# language.

  • Anonymous
    December 24, 2012
    Thanks Micheal! it really helped us resolve this issue!

  • Anonymous
    December 26, 2012
    The comment has been removed

  • Anonymous
    January 10, 2013
    I´m trying to send html email from a lightswitch application but when i try to get the image from the sql db it does not works. I used <img src="<%=me.opportunities.team.picture%>" width="80" height="80">. Any idea?

  • Anonymous
    November 30, 2013
    Hello Everyone, Beth for what it's worth I'm using hotmail and I had to add :    smtp.EnableSsl = True to the helper class and it worked like a charm after that. Thanks :)

  • Anonymous
    December 11, 2013
    I am attempting to use the Send via Outlook. Ive added the codes, but nothing happens when i click the Button. I dont even get an error. Ive tried it with my Outlook running even and the same thing happens.  Not sure how to troubleshoot when I dont even get an error.

  • Anonymous
    May 08, 2014
    The comment has been removed

  • Anonymous
    July 09, 2014
    Hello. is it possible to "Sending Email via an Outlook Client" with an Lightswitch HTML-Client?

  • Anonymous
    December 17, 2015
    Beth, your blogs have been a lifesaver for my venture into Lightswitch! I am having an issue with an error that "SendMail is not a member of SMTPMailHelper" which makes no sense because I can see it clear as day in your code.