Creating Email Newsletters with patNewsletter (part 2)

Learn to manage subscribers and customize newsletters with patNewsletter.

Sign In

In the first part of this two-part series on patNewsletter, I showed you that managing a newsletter is as easy as clicking your way through a series of menus. I started with an introduction to the intricacies of creating a newsletter, adding topics, creating new issues, and adding content to your newsletter before sending it out. And to ensure that your newsletter doesn't remain on the drawing board for too long, I also gave you some tips on how to implement a workflow for your newsletter.

Today, I'm going to get into more advanced aspects of the topic, showing you how to customize the format of the newsletter. This will be followed by a demonstration of the built-in subscriber management system, and customization of the forms that come bundled with the application. All the templates used in this application are based on the powerful patTemplate technology...so if you already know how this works, you're going to be ahead of the game already.

Security is of paramount importance - after all, you don't want hackers to walk in and steal your content - and to that end, I will also show you how to use HTTP authentication to protect the patNewsletter administration module. Finally, I will talk about patExtras, nifty little tools that allow you to keep your installation of the patNewsletter application updated at all times.

Let's get started, shall we?

Laying It Out

The layout of your newsletter is driven by the patTemplate template engine. Developed by Stephan Schmidt - the author of patNewsletter - patTemplate is a PHP-based template engine designed, in the author's words, to "help you separate program logic or content from layout". Read more about it at http://www.melonfire.com/community/columns/trog/article.php?id=130

As you might remember from the first part of this article, I specified in the configuration file that all templates would be located in the "templates/" directory, for both administration and subscription interfaces. The templates associated with the newsletter are a part of the administration section of the application and are present in the "admin/templates" directory under the root directory of the application.

Find a file named "patNlNewsletter.txt.tmpl" and open it in your favourite text editor.Here's what you'll see:

<patTemplate:tmpl name="subject" type="condition" conditionvar="SUBJECTPREFIX" whitespace="trim">
    <patTemplate:sub condition="default">
{NL_SUBJECTPREFIX} #{ISSUE_ISSUE}: {ISSUE_SUBJECT}
    </patTemplate:sub>
</patTemplate:tmpl>

<patTemplate:tmpl name="body" whitespace="keep">
{NL_HEADER}

{ISSUE_INTRODUCTION}

------------------------------------------------------------------------

In dieser Ausgabe:
<patTemplate:tmpl name="toc">
 - {DETAILS_TITLE}
</patTemplate:tmpl>

<patTemplate:tmpl name="details">
:::{DETAILS_TITLE}:::

{DETAILS_BODY}

</patTemplate:tmpl>

------------------------------------------------------------------------
{NL_FOOTER}
</patTemplate:tmpl>

A closer look, and you'll see that this template is made up of two distinct sub-templates, one for the body and one for the subject line - pretty much what you would expect for a email newsletter!

Let's take a closer look at each of them, shall we? Here's the sub template for the subject line:

<patTemplate:tmpl name="subject" type="condition" conditionvar="SUBJECTPREFIX" whitespace="trim">
    <patTemplate:sub condition="default">
{NL_SUBJECTPREFIX} #{ISSUE_ISSUE}: {ISSUE_SUBJECT}
    </patTemplate:sub>
</patTemplate:tmpl>

The code here leverages off conditional template support in the patTemplate class. "Conditional templates" function much like a series of "if-else" conditional statements - they allow you to display different output depending on how a particular, user-defined condition is evaluated. A conditional template typically contains a number of sub-templates, each keyed against a particular variable; depending on the value of that variable, the appropriate sub-template is extracted and used.

In the example above, the conditional variable is called "SUBJECTPREFIX" and the only condition allowed, at this point of time, is the default value. But there is still scope for playing around with the template - after a little investigation, I uncovered the six variables that you could include in the subject line:

  • name: the name given to the newsletter
  • subjectprefix: the prefix provided for the newsletter at the time of creation
  • listowner: the email address specified in the "Reply-to address" field
  • description: the detailed description about the newsletter
  • issue: the issue number associated with the current issue of the newsletter
  • subject: the subject specified for this particular issue of the newsletter

If you look at the default template, you will notice that the subject line already contain the issue number, issue subject and the subject prefix. Here is a sample subject line based on the default template:

[hitg] #2: One Million Or Bust !!

Let's tweak the template and see if we can make things a little more interesting:

<patTemplate:tmpl name="subject" type="condition" conditionvar="SUBJECTPREFIX" whitespace="trim">
    <patTemplate:sub condition="default">
Issue # {ISSUE_ISSUE} of "{NL_NAME}" on * {ISSUE_SUBJECT} * by -> {NL_LISTOWNER} <-
    </patTemplate:sub>
</patTemplate:tmpl>

Here is the output:

Issue # 2 of "hitg" on * One Million Or Bust !! * by -> hitg@usa.net <-

Note the use of uppercase characters as well as the curly braces around the variables names. These are some conventions that must be followed across all patTemplate templates.

A Little Body

Time to move on to the body of the newsletter:

<patTemplate:tmpl name="body" whitespace="keep">
{NL_HEADER}

{ISSUE_INTRODUCTION}

------------------------------------------------------------------------

In dieser Ausgabe:
<patTemplate:tmpl name="toc">
 - {DETAILS_TITLE}
</patTemplate:tmpl>

<patTemplate:tmpl name="details">
:::{DETAILS_TITLE}:::

{DETAILS_BODY}

</patTemplate:tmpl>

------------------------------------------------------------------------
{NL_FOOTER}
</patTemplate:tmpl>

At first glance, this looks pretty complicated. So, let's break it down into smaller bits for clarity. First, the outermost template is titled "body". Within this template, we have a couple of sub-templates. The first one is called "toc" and displays the list of the articles associated with this issue of the newsletter, one by one. This is followed by the "details" template, the most important one as it is responsible for taking each article associated with the selected issue of the newsletter and rendering it. As noted previously, articles are displayed in the same order as they are entered.

Finally, here are some parameters that have been used in the default template:

  • header: the header of the newsletter, common for each issue of the newsletter
  • footer: the footer that comes at the bottom of all issues
  • introduction: the introduction provided for the issue

By the way, the phrase "In dieser Ausgabe" is German for "In this issue"...just in case you were wondering.

Let's take a look at the template that I came up with for my own newsletter:

<patTemplate:tmpl name="subject" type="condition" conditionvar="SUBJECTPREFIX" whitespace="trim">
    <patTemplate:sub condition="default">
Issue # {ISSUE_ISSUE} of "{NL_NAME}" on * {ISSUE_SUBJECT} * by -> {NL_LISTOWNER} <-
    </patTemplate:sub>
</patTemplate:tmpl>

<patTemplate:tmpl name="body" whitespace="keep">
{NL_HEADER}

{ISSUE_INTRODUCTION}

<>---------------------------------------------<>

In this issue:
<patTemplate:tmpl name="toc">
 - {DETAILS_TITLE}
</patTemplate:tmpl>

<patTemplate:tmpl name="details">
---> {DETAILS_TITLE} <---

{DETAILS_BODY}

</patTemplate:tmpl>

_.:*~*:._.:*~*:._.:*~*:._.:*~*:._.:*~*:._.:*~*:._.:*~*:._.:*~*:._

{NL_FOOTER}
</patTemplate:tmpl>

As you can see, I haven't done much - apart from adding a little ASCII art, I haven't ventured into any drastic design change.

Fooling The People

patNewsletter come with a built-in subscriber management system that you can implement in no time at all. In fact, you can get your show on the road almost instantly, by pointing your browser to the following URL: http://localhost/patNewsletter/newsletter.php

Take a look at the simple form that comes up in your browser:

By default, you will see a page that allows you to login and modify your subscription. But you still need to register for the newsletter - you can do this by clicking on the "registration" link provided at the bottom of this page. The registration form is short and sweet, as seen from the screenshot below:

Every subscriber needs to fill up the "Email" and "Password" fields. Additional personalization is provided in the form of allowing the user to select the topics that he/she wishes to receive in the newsletter. These are the same topics you created when defining the framework of your newsletter. As a result, a user can opt out of any topic of the newsletter and thus personalize the content he/she receives to some extent.

Once users sign up, they can easily modify their preferences using the same URL, after entering their login name and password:

As you can see, this screen also offers the user the option to "Delete" his/her subscription - a single click of the button and they can bid adieu to your newsletter forever!

As an administrator of the newsletter, you can always monitor your subscribers and their preferences using the "Subscription" link in the administration module. Here what this screen looks like:

Under The Skin

Now that I have introduced you to the subscription interface, it's time to look underneath the skin. Not surprisingly, the location of the templates that render the subscription screens above are also driven by the parameters specified in the configuration file. By default, these templates are located in the "templates/" directory under the application installation directory:

There are two files in this "templates" folder:

  • the "patNlLogin.tmpl" file, used to drive the login page

  • the "patNlSubscription.tmpl" file, used to render the form(s) that appear when a user signs up for the newsletter or logs on to modify his/her preferences.

The first template file "patNlLogin.tmpl" is pretty straight forward to understand. I will not replicate the code here as the templates are fairly large; instead, I'll focus in on the parts that you might want to modify. The first is the manner in which the name of the newsletter and its description are displayed to the user.

<patTemplate:tmpl name="page">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>

<table border="0" cellpadding="0" cellspacing="0" width="500">
    <tr>
        <td>
            <p>
                <b>{NEWSLETTER_NAME}</b><br><br>
                <i>{NEWSLETTER_DESCRIPTION}</i>
            </p>
</table>

</html>
</patTemplate:tmpl>

You can also add the "Reply-to:" email address, by using the variable "{NEWSLETTER_LISTOWNER}" in the template above. The rest of the fields associated with the newsletter (header, footer et al) are only applicable to the newsletter itself and do not find place here.

The next part of this template deals with the error messages to be displayed to the user in various situations (entering an invalid email address and so on). You can conveniently modify these messages to your liking in this template file.

    <patTemplate:tmpl name="errorList" visibility="hidden">
    <tr>
        <td>
            <p class="error">
                <b>Please correct the following errors:</b><br>
        <patTemplate:tmpl name="error" type="condition" conditionvar="errorcode">

            <patTemplate:sub condition="EMAIL_MISSING">
                &middot;&nbsp;Please enter your eMail adress.<br>
            </patTemplate:sub>

            <patTemplate:sub condition="EMAIL_INVALID">
                &middot;&nbsp;Your eMail adress is not valid.<br>
            </patTemplate:sub>

            <patTemplate:sub condition="PASSWD_MISSING">
                &middot;&nbsp;Please enter a password.<br>
            </patTemplate:sub>

            <patTemplate:sub condition="PASSWD_INCORRECT">
                &middot;&nbsp;The password you entered is incorrect.<br>
            </patTemplate:sub>

            <patTemplate:sub condition="NOT_SUBSCRIBED">
                &middot;&nbsp;You are not subscribed to our newsletter.<br>
            </patTemplate:sub>

        </patTemplate:tmpl>

Finally, you have the two fields that actually drive the login process - the email address and the password fields. I would recommend that you not mess with these fields.

<form method="post" action="{DISPATCHER}">

            <table border="0" cellpadding="0" cellspacing="5">
                <tr>
                    <td>Your eMail:</td>
                    <td><input type="text" name="email" size="30" maxlength="200" value="{SUBSCRIPTION_EMAIL}"></td>
                </tr>
                <tr>
                    <td>Your password:</td>
                    <td><input type="password" name="passwd" size="30" maxlength="20" value="{SUBSCRIPTION_PASSWD}"></td>
                </tr>
                <tr>
                    <td colspan="2" align="center"><input type="submit"></td>
                </tr>
            </table>

</form>

If you wish to modify the HTML above, remember that you should always include these two text fields along with the <form> element.

Moving On

Let's move to the other template file, "patNlSubscription.tmpl". If you thought the previous template was bad, you're gonna feel a lot worse when you see this one.

As usual, certain portions of the template can be tweaked at will, while others should not be modified if you want to ensure a smooth sign-up process for your subscribers.

As with the previous template, you can modify the manner in which information about the newsletter is displayed to the user. You also have a list of error messages to be displayed to the user - feel free to change the text to your requirements.

The next bit of the template is the critical part - it displays the fields for the user to sign up as well as the topics that the user can sign up for when subscribing to the newsletter. Take a look:

<table border="0" cellpadding="0" cellspacing="5">

<patTemplate:tmpl name="userdata" visibility="hidden">
<!-- This part is left out when working with external user data -->
<tr>
    <td>Your eMail:</td>
    <td><input type="text" name="subscription[email]" size="30" maxlength="200" value="{SUBSCRIPTION_EMAIL}"></td>
</tr>
<tr>
    <td>Your password:</td>
    <td><input type="password" name="subscription[passwd]" size="30" maxlength="20" value="{SUBSCRIPTION_PASSWD}"></td>
</tr>
<tr>
    <td>Your password (repetition):</td>
    <td><input type="password" name="subscription[passwd2]" size="30" maxlength="20" value="{SUBSCRIPTION_PASSWD2}"></td>
</tr>
</patTemplate:tmpl>

<tr>
    <td colspan="2">
        <b>Topics</b>
        <table border="0" cellpadding="0" cellspacing="0">
            <patTemplate:tmpl name="topic" type="condition" conditionvar="TOPIC_SUBSCRIBED">

            <patTemplate:sub condition="no">
            <tr>
                <td><input type="checkbox" name="subscription[topics][]" value="{TOPIC_ID}"></td>
                <td>{TOPIC_NAME}</td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td><i>{TOPIC_DESCRIPTION}</i></td>
            </tr>
            </patTemplate:sub>

            <patTemplate:sub condition="yes">
            <tr>
                <td><input type="checkbox" name="subscription[topics][]" value="{TOPIC_ID}" checked></td>
                <td>{TOPIC_NAME}</td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td><i>{TOPIC_DESCRIPTION}</i></td>
            </tr>
            </patTemplate:sub>

            </patTemplate:tmpl>
        </table>

As you can see, the fields are pretty self explanatory. They start with the email address and subscriber password fields. This is followed by the list of topics associated with the newsletter. Each topic is accompanied by a little description and a checkbox that will be checked or unchecked, based on whether you think users should receive this topic by default.

Once again, my suggestions would be to leave this part of the template as it is, unless you are very sure of what you are doing.

Locking It Down

If there is one drawback to the patNewsletter application, it is the lack of security for the administration module. By default, patNewsletter leaves the entire administration section totally unprotected and open to malicious attacks. If you're using the Apache Web server (you probably are), you can access the server's authentication features to add basic security to this section.

In order to illustrate how this works, let's consider a simple example. Let's assume the existence of the following directory structure:

/usr/local/apache/htdocs/patNewsletter/
                                  newsletter.php
                                  /admin/
                                      guestbook.php

Now, let's suppose that I want to protect the directory "admin". It's fairly simple to do with HTTP authentication.

The first step is to ensure that your Apache build includes support for the "mod_auth" module. You can check this by executing the Apache binary with the "-l" command-line option. If you don't see "mod_auth" in the list that appears on your screen, you'll need to recompile Apache with support for that module.

Next, check Apache's configuration file, "httpd.conf", and ensure that the option.

AllowOverride All

is present in the section for the server document root. This allows you to override global server settings via per-directory ".htaccess" control files.

Next, create a file named ".htaccess" in the "admin" directory, and put the following lines into it:

AuthType Basic
AuthUserFile /usr/local/apache/users
AuthName "patNewsletter Administration Module"
Require valid-user

This tells the server that access to the "admin" directory (the directory in which the ".htaccess" file is located) is to be controlled, and access is to be granted to users based on the username/password information in the file "/usr/local/apache/users"

The final step is to create the "users" file. Change to the "/usr/local/apache" directory (or whichever directory you've decided to store the user data in) and use the "htpasswd" command:

$ htpasswd -c users john
New password: ****
Re-type new password: ****
Adding password for user john

You can add more users to this file if you like (remember to omit the "-c" parameter for all subsequent additions, as that parameter creates a brand-new, empty file).

Remember not to store the "users" file in a directory under the server document root, or else malicious users will be able to view and download the password database through a browser.

Now, attempt to access the "admin" directory via your Web browser. The browser should pop up a dialog box and prompt you for a username and password. Access to the "admin" directory will be granted only if you enter a correct username and password, as defined in the "users" file.

Note that this is very primitive authentication, and can substantially add to the load on your Web server if it involves a large number of users. For a more comprehensive solution, take a look at http://www.melonfire.com/community/columns/trog/article.php?id=115

Over And Out

That's about it for this two-part series on patNewsletter.

Today, I showed you how to customize the layout of the newsletter, which is based on the very powerful patTemplate template engine. Next, you saw the built-in subscriber management system and how you can customize the look and feel of the subscription management forms to meet your requirement - this is essential as newsletters are often used as a co-branding tool for their respective Web sites. We all know that security is critical and so I wrapped it all up by showing you how to leverage off the simple but powerful HTTP authentication mechanism to protect the patNewsletter administration module.

In case you'd like to learn more about the topics discussed in this tutorial, take a look at the following links:

The official patNewsletter Web site, at http://www.php-tools.de/

Template-Based Web Development With patTemplate, at http://www.melonfire.com/community/columns/trog/article.php?id=130

User Authentication With Apache And PHP, at http://www.melonfire.com/community/columns/trog/article.php?id=115

Until next time...stay healthy!

This article was first published on30 Mar 2004.