A critical vulnerability was discovered in React Server Components (Next.js). Our systems remain protected but we advise to update packages to newest version. Learn More

cecilia@nansen.se
Jul 1, 2011
  5984
(0 votes)

Implementing a simple email queue in EPiServer Commerce

Recently I’ve been working with a Commerce project where when a customer has placed an order we wanted to send a confirmation email. In the EPiServer Commerce sample site the code to send the confirmation email is in the code behind of the cart checkout control. This isn’t a good practice as if something goes wrong with the email sending, for example, if the SMTP configuration is incorrect, then the user will see an error saying something went wrong with their order, which in this case is not true.

What we decided to do was to queue up an email request using the EPiServer Dynamic Data Store and then use an EPiServer Scheduled Job to service the email queue and send out the emails.

First of all we created a simple class with the information needed to send the email:

using System;
using EPiServer.Data.Dynamic;

namespace Project.Foundation.CMS.Helpers
{   
    [EPiServerDataStore(AutomaticallyCreateStore = true)]
    public class OrderEmailToBeSent
    {
        public int OrderId { get; set; }
        public Guid Id { get; set; }
    }
}

Then when an order is placed we created an instance of the above class, set it’s properties and saved it in the DDS:

private void SaveOrderId(int orderId)
{
     var store = typeof(OrderEmailToBeSent).GetStore();
     var orderEmailToBeSent = new OrderEmailToBeSent { OrderId = orderId };
     store.Save(orderEmailToBeSent);
}

The Scheduled Job class gets the items from the Dynamic Data Store, loads the order from the Commerce system, sends an email to the customer, and then deletes the item from the DDS:

[ScheduledPlugIn(DisplayName = "Send order emails")]
 class SendOrderEmails
 {
     public static string Execute()
     {
         var store = typeof(OrderEmailToBeSent).GetStore();
         int skip = 0;
         const int count = 50;
         while (true)
         {
             var items = store.Items<OrderEmailToBeSent>().Skip(skip).Take(count);

             if (items.Count() == 0)
                 break;

             foreach (var orderEmailToBeSent in items)
             {
                 var order = CartHelper.FindOrder(orderEmailToBeSent.OrderId);

                 SendEmail(order, "order-purchaseorder-notify");
                 store.Delete(orderEmailToBeSent);
             }

             skip += count;
      }
         return "Success!";
     }
 }

And the code for sending the email:

private static void SendEmail(PurchaseOrder order, string template)
{
      // Add input parameter
      var dic = new Dictionary<string, object>();
      dic.Add("OrderGroup", order);

      // Execute template processor
      var body = TemplateService.Process(template,                  
Thread.CurrentThread.CurrentCulture, dic); // Send out emails var msg = new MailMessage(); msg.From = new MailAddress("store@yourcompany.com"); msg.To.Add(new MailAddress("customer@customer.com", " - " + order.Name)); msg.Subject = "Subject"; msg.Body = body; msg.IsBodyHtml = true; var client = new SmtpClient(); client.Send(msg); }

The TemplateService class used above takes an XSL template and transforms it into an HTML email. See this article for more details about this.

Jul 01, 2011

Comments

Please login to comment.
Latest blogs
A day in the life of an Optimizely OMVP: Learning Optimizely Just Got Easier: Introducing the Optimizely Learning Centre

On the back of my last post about the Opti Graph Learning Centre, I am now happy to announce a revamped interactive learning platform that makes...

Graham Carr | Jan 31, 2026

Scheduled job for deleting content types and all related content

In my previous blog post which was about getting an overview of your sites content https://world.optimizely.com/blogs/Per-Nergard/Dates/2026/1/sche...

Per Nergård (MVP) | Jan 30, 2026

Working With Applications in Optimizely CMS 13

💡 Note:  The following content has been written based on Optimizely CMS 13 Preview 2 and may not accurately reflect the final release version. As...

Mark Stott | Jan 30, 2026

Experimentation at Speed Using Optimizely Opal and Web Experimentation

If you are working in experimentation, you will know that speed matters. The quicker you can go from idea to implementation, the faster you can...

Minesh Shah (Netcel) | Jan 30, 2026