Managing e-mail subscriptions in EPiServer

This article was migrated from an older iteration of our website, and it could deviate in design and functionality.


In this post we create an admin plugin for EPiServer which allows administrators to add or remove e-mail subscribers.

Estimated read time : 11 minutes

Jump to

Background

E-mail subscription in EPiServer CMS 5 is based on ASP.NET profiles. Starting and stopping subscriptions through code is easy, but I was missing a plugin where administrators could easily add new subscribers, remove existing subscriptions and list all subscribers. This post explains how to implement such a module, and I’ll use a module for managing press release subscriptions as an example.

Functionality of the EPiServer subscriptions plugin

The module should support the following:

  • List all subscribers for swedish and english press releases, respectively
  • Allow administrators to add a subscriber for either swedish or english press releases
  • Allow administrators to remove a subscription

And obviously we want some sweet AJAX behavior when the plugin is loaded! :)

We’ll click Press Release Subscribers in the Tools list:

image

The plugin (an .ASPX page) will load, but we won’t load the subscriber list until the page has rendered:

image

Next we’ll get a list of existing subscribers, and we’re also able to add additional subscribers:

image

We use the Subscription dropdown to specify what a new subscriber should subscribe to:

image

Whenever we change the subscription type the subscriber list will be refreshed to list all subscribers for the selected subscription:

image

Now, to add a new subscriber to the selected subscription we simply specify the e-mail address and click Save:

image

We’ll then see a brief AJAX progress indicator…

image

…followed by a confirmation that the subscriber has been added:

 image

And the subscriber list has been refreshed to include the newly added subscriber:

 image

Now, if we want to delete a subscription we simply click Delete. This will bring up a dialog:

image

We’ll confirm by clicking Delete and once again an AJAX progress indicator is displayed briefly…

image

…followed by a confirmation message:

image

Ok, you get the idea of how it works from a user’s perspective. Now, let’s look at how it’s implemented!

Implementing a subscription management plugin for EPiServer

I’ll describe the key parts of the admin plugin to avoid this post from getting to cluttered. But feel free to post comments if you have any questions regarding something I may have left out!

First, we’ll create a new class inheriting from Page. Then we’ll add the GuiPlugIn attribute to set the properties of the admin plugin:

[GuiPlugIn(
   Area = PlugInArea.AdminMenu,
   DisplayName = "Press Release Subscribers",
   Url = "/Templates/Public/Pages/Plugins/SubscribersList.aspx",
   RequiredAccess = AccessLevel.Administer)]
public partial class SubscribersList : Page
{
   // TODO Add page logic
}

Next we’ll add a ScriptManager and an UpdatePanel to AJAX-enable our plugin:

<asp:UpdatePanel ID="pnlList" runat="server">
   
   <ContentTemplate>
   <!-- Subscriber list goes here -->
   </ContentTemplate>
 
</asp:UpdatePanel>

I’ll also add an UpdateProgress control. Note that I’ve set an ID for the <P> tag to allow me to change the text within the UpdateProgress control client-side:

<asp:UpdateProgress AssociatedUpdatePanelID="pnlList" DisplayAfter="50" ID="progress" runat="server">
   <ProgressTemplate>
      <p id="status-message"></p>
      <img src="/Templates/Gfx/ajax-loader-admin.gif" alt="Loading" />
   </ProgressTemplate>
</asp:UpdateProgress>

I can now customize the message within the progress indicator when a button is clicked like so:

<asp:Button Text="Delete" OnClientClick="$get('status-message').innerHTML='Deleting subscription...';" ID="btnConfirmDelete" runat="server">

List all subscribers

Within the UpdatePanel’s ContentTemplate element I’ll add a GridView control to help me list all subscribers:

<asp:GridView
   AutoGenerateColumns="false"
   BorderStyle="None"
   AllowPaging="true"   
   PageSize="50"
   EnableSortingAndPagingCallbacks="false"
   AutoGenerateDeleteButton="true"
   onpageindexchanging="subscriberListSelectedIndexChanged"
   OnRowDeleting="subscriberListDeleting" 
   ID="grdSubscribers"
   runat="server">
 
   <Columns>
      <asp:BoundField DataField="Email" HeaderText="E-mail" />
      <asp:BoundField DataField="Lang" HeaderText="Language" />
      <asp:BoundField DataField="Updated" HeaderText="Last updated" />
   </Columns>
 
   <EmptyDataTemplate>No subscribers added</EmptyDataTemplate>
 
</asp:GridView>

Now, by databinding this GridView to a DataTable we’ll get a list of subscribers, complete with paging:

// Create data table for the grid view
DataTable dt = new DataTable("tblSubscriptions");
dt.Columns.Add("Email", typeof(string));
dt.Columns.Add("Updated", typeof(DateTime));
dt.Columns.Add("Lang", typeof(string));
 
// Primary key required for paging
dt.PrimaryKey = new DataColumn[1] { dt.Columns["Email"] };
 
// Iterate all ASP.NET profiles to find subscribers
foreach (ProfileInfo pi in ProfileManager.GetAllProfiles(System.Web.Profile.ProfileAuthenticationOption.All))
{
   // Get the EPiServer profile
   EPiServerProfile profile = EPiServerProfile.Get(pi.UserName);
 
   // Check if the profile is subscribing
   if(profile.SubscriptionInfo.IsSubscribingTo(subscriptionTargetPageLink, ddLanguage.SelectedValue))
   {
      dt.Rows.Add(new object[3] { profile.Email, profile.LastUpdatedDate, ddLanguage.SelectedValue });
   }
}
 
// Databind the subscriber list
grdSubscribers.DataSource = dt;
grdSubscribers.DataBind();

Stop a subscription

The GridView control includes a column including a Delete link:

image

As we saw in the markup before, the OnRowDeleting event has been hooked up to by an event handler called subscriberListDeleting. The event handler simply displays controls for verifying that the subscriber should be deleted:

image

Here’s how it’s done:

/// <summary>
/// Handles the "Delete" command in the grid view
/// </summary>
protected void subscriberListDeleting(object sender, GridViewDeleteEventArgs e)
{
   // Get the e-mail from the selected GridView row
   string selectedEmailAddress = grdSubscribers.Rows[e.RowIndex].Cells[1].Text;
   
   // Set the confirmation message
   litConfirmDeleteMessage.Text = string.Format("<p>Please confirm you wish to delete this subscriber: <strong>{0}</strong></p>",selectedEmailAddress);
 
   // Set the command argument of the Delete button
   btnConfirmDelete.CommandArgument = selectedEmailAddress;
 
   // Display the confirmation controls
   phConfirmDelete.Visible=true;
}

The Delete button’s CommandName property has been set to “Delete”. The OnCommand event is then hooked up to the following event handler (code abbreviated for clarity):

/// <summary>
/// Handles commands executed inside an action area
/// </summary>
protected void buttonActionCommandHandler(object sender, CommandEventArgs e)
{
   switch (e.CommandName)
   {
      case "Delete":
         // Get profile to unsubscribe based on command argument
         EPiServerProfile profileToUnsubscribe = EPiServerProfile.Get((string)e.CommandArgument);
 
         // Remove subscription
         profileToUnsubscribe.SubscriptionInfo.UnSubscribe(subscriptionTargetPageLink, ddLanguage.SelectedValue);
 
         // Save profile
         profileToUnsubscribe.Save();
 
         break;
   }
}

Add a new subscriber

To start a new EPiServer subscription we have a set of controls for specifying the type of subscription and the e-mail address of the subscriber:

image

Code similar to the following is executed when the Save button is clicked:

IList<EPiServerProfile> profiles = EPiServerProfile.GetProfiles(address);
 
if (profiles.Count > 1) // Specified address returned group
{
   litGenericConfirmationMessage.Text = string.Format("Specified e-mail address returned {0} profiles. Subscriptions cannot be added for groups.");
   break;
}
else // Single profile, or non-existing profile
{
   // Get the existing/new profile
   EPiServerProfile profile = profiles[0];
 
   // Cancel if subscription already exists
   if (profile.SubscriptionInfo.IsSubscribingTo(subscriptionTargetPageLink))
   {
      litGenericConfirmationMessage.Text = string.Format("Subscription to <strong>{0}</strong> is already active for e-mail address <strong>{1}</strong>.", subscriptionTargetPage.PageName, address);
      break;
   }
 
   // Add the subscription
   profile.Email = address;
 
   profile.SubscriptionInfo.SubscribeTo(subscriptionTargetPageLink, ddLanguage.SelectedValue);
 
   profile.Save();
}

I’ve left out most of the “estethics” logic, but I hope you get the idea! Comments and feedback are welcome as usual!