-
Jonathan Hedstrom
Lead Developer

We recently remade our company newsletter from a simple plain text affair to a simple, but elegant HTML newsletter. The first attempt at this utilized a combination of the Simplenews and Mimemail modules. This, however, didn't work as expected, so we went with a partially custom solution.
The Simplenews module is still at the heart of our new newsletter, but a few custom tweaks (no hacking of the original module, of course) were added to make things simpler on Thomas when he creates these.
The first addition, was a preview button to view the newsletter using the themed HTML template (the one used to actually mail the newsletter, rather than the node template for viewing on the site). This was a simple matter of altering the newsletter node form, and adding a callback to compile the preview.
/** * Implementation of hook_form_alter(). * * Add a preview email functionality. */ function os_newsletter_form_alter(&$form, $form_state, $form_id) { switch ($form_id) { case 'simplenews_node_form': $form['buttons']['preview_newsletter'] = array( '#type' => 'submit', '#value' => t('Preview Email Format'), '#submit' => array('os_newsletter_build_preview'), '#weight' => 15, ); break; } }
This adds a third (or fourth, for edits) button to the node form for previewing. The callback function mimics the work Simplenews does when it is sending the message:
/** * Build email preview. */ function os_newsletter_build_preview($form, &$form_state) { $node = node_form_submit_build_node($form, $form_state); // Mimic simplenews, and node_preview functionality. $cloned_node = drupal_clone($node); $cloned_node = node_build_content($cloned_node, FALSE, TRUE); $content = drupal_render($cloned_node->content); $cloned_node->body = $content; unset($cloned_node->teaser); node_invoke_nodeapi($cloned_node, 'alter', FALSE, TRUE); $form_state['node_preview'] = theme('simplenews_newsletter_body', $cloned_node->body, check_plain($cloned_node->title), ''); }
The node module itself picks up on the 'node_preview' element in the $form_state variable and takes care of displaying the preview. With some additional work, this may be fed back upstream in the form of a patch to the Simplenews module.
The next step was to construct a template for the email. Since HTML email is not a standard, working with email clients is akin to travelling back in time to 1996 or so in terms of HTML and CSS. No CSS layout, no external stylesheets (web mail clients tend to remove head tags). As such, the template was a mess of tables and inline style declarations, but it gets the job done. Simplenews outputs the email body via the theme_simplenews_newsletter_body() function. As such, our new HTML email template went into a function named phptemplate_simplenews_newsletter_body().
The last thing left to do was convince simplenews to send the mail as multipart containing both plain text and HTML parts. The obvious choice for this appeared to be the Mimemail module, but once I started testing it, soon discovered that it was too sophisticated for what needed to be done.
The problem was that it took all images and attached them to the email, instead of linking externally, which has, in the absence of any standards, become the standard for HTML email. Attaching the images and sending those out with each email results in a huge bandwidth hit, and also unnecessarily bloats the recipients inboxes. Additionally, we wanted the plain text portion to be constructed manually instead of automatically, thus retaining complete control over the format and content. The Simplenews/Mimemail route constructs the plain text version from the HTML version, and the results, in our case, were not pretty.
Fortunately, by implementing hook_mail_alter, constructing multipart emails is very straightforward:
/** * Implementation of hook_mail_alter(). * * Used to create a custom, multipart MIME email message. */ function os_newsletter_mail_alter(&$message) { switch ($message['id']) { case 'simplenews_node': case 'simplenews_test': $node = $message['params']['context']['node']; $footer = $message['body']['footer']; // HTML part $html = theme('simplenews_newsletter_body', $node->body, check_plain($node->title), '') . "\n\n" . nl2br($footer); // Text part $text = theme('os_newsletter_newsletter_plain_text', $node->field_plain_text[0]['value']) . "\n\n" . $footer; $message['body'] = _os_newsletter_construct_multipart($text, $html, $message); } }
/** * Build the message body for a MIME multipart email. */ function _os_newsletter_construct_multipart($text, $html, &$message) { $boundary = '----=_NextPart_' . md5(uniqid(time())); // Set headers. $message['headers']['Content-Type'] = "multipart/alternative; charset=utf-8; boundary=\"$boundary\""; $message['headers']['MIME-Version'] = '1.0'; // Add text part, which is the alternative. $body = "This is a multi-part message in MIME format.\n"; $body .= "\n--$boundary\n"; $body .= "Content-Type: text/plain; charset=UTF-8; format=flowed;\n"; $body .= "Content-Transfer-Encoding: 8bit\n\n"; $body .= $text; // Add HTML part. $body .= "\n--$boundary\n"; $body .= "Content-Type: text/html; charset=UTF-8; format=flowed;\n"; $body .= "Content-Transfer-Encoding: 8bit\n\n"; $body .= $html; // Add closing boundary. $body .= "\n--$boundary--\n"; return $body; }
So with a relatively simple custom module, our newsletter went from a mess of asterisks and dashes for formatting, to a mess of inline style attributes and tables...but it looks a lot better.
And also, when testing HTML newsletters using Lorem Ipsum, Gmail has absolutely no idea what ads to display.
Tagged as: Drupal, Drupal 6, HTML email, Simplenews
Desparetly need this in Simplenews
The preview function you mentioned is definitely needed in Simplenews. Perhaps you could post a feature request in Simplenews issue que with a link back to this article.
Great article
Tnx for the article. It will be very very usefull.
Interesting discussion
There's a good page at drupal.org that covers this as well http://drupal.org/node/268404.
Mimemail seems to link externally to photos fine for me - I found mimemail only included images as attachments when I was using a filter than included line break converter (like Full HTML). drupal_mail performs a drupal_wrap_mail, so when mimemail later performs a checkmarkup, line break converter filter adds in a whole lot of break tags destroying the message.
Thanks for the great write up
Email newsletters are such a nightmare. A preview in Simplenew for the email rather than the node is a big help, but testing these things is a nightmare.
Every version of MS Outlook renders them a bit differently, and the number of browser / webmail combinations gives me a headache!
Can't we all call a truce and go back to plain text!
html email template
I'm trying to get drupal to send a clean html email newsletter using the same module that you have used but can't find a way to remove the css added by Drupal. In other words, when i receive a test copy of the newsletter the source code has all the css from the website it is being sent from.
Is it a matter of creating a custom.tpl.php file and using the function phptemplate_simplenews_newsletter_body() to direct the output to that file?
Great article by the way.
Hey Joshua, I assume you're
Hey Joshua,
I assume you're using the mimemail module for sending the HTML email? Another reason we decided to go with the custom approach described above was mimemail's behavior of attaching all of the site's CSS to every email. This adds up to a lot of CSS, and very large and complicated HTML emails.
The above method, which relies on re-theming the output of simplenews, sends only the CSS specified in our overriding theme function.
code snippet
I have tried re-themeing the output using content templates module but the extra css still gets put in there. Would you be able to send me a code snippet showing how you get around around this? I would appreciate it very much as i have been stuck on this problem for the past few days.
@Joshua & Jonathan - it's
@Joshua & Jonathan - it's easy to change the css that Mimemail uses for sending html. Just drop in a 'mail.css' file with the appropriate css in to your theme. No re-theming necessary.
Mimemail's
function theme_mimemail_message()does a$styles = path_to_theme() .'/mail.css';before it resorts to using all of Drupal's css.@Patrick Harris
Good to know. Thanks.
worked a treat
Thank you Patrick, the mail.css file has overwritten the drupal css code in the email. The only issue i have now is the node title being printed above the body. This is a problem because our newsletter uses red borders and the title is being inserted above the top border. I would rather it be placed inside the body so i can style it. What is the proper location for disabling this from being displayed?
@Joshua - Simplenews has a
@Joshua - Simplenews has a themeable function:
function theme_simplenews_newsletter_body($body, $title, $language) { $output = '<h2>'. $title ."</h2>\n"; $output .= $body; return $output; }To override this, just put a function named phptemplate_simplenews_newsletter_body in your theme's template to override it:
function phptemplate_simplenews_newsletter_body($body, $title, $language) { // alter the following how you wish: $output = '<h2>'. $title ."</h2>\n"; $output .= $body; return $output; }You can also use your theme's name instead of 'phptemplate'.
@ Patrick
I tried adding the function to the bottom of my template.php (customised zen theme) file but it doesn't appear to be getting called. So i just hacked the simplenews.module and commented out a line "$node->body = ''. $node->title ."\n". $node->body;", as seen below.
function theme_simplenews_newsletter($node, $tid) { $term = taxonomy_get_term($tid); $node->subject = '['. $term->name .'] '. $node->title; //$node->body = '<h2>'. $node->title ."</h2>\n". $node->body; return $node; }I know you are not supposed to hack Drupal core or module code but it works. Thanks for your help guys.
Oh - to get it working, you
Oh - to get it working, you need to clear the theme registry. Visiting the theme page should do it, or go to site configuration/performance and click on 'clear cached data' button, or you can use the
drupal_rebuild_theme_registry()function.Thanks for this post and the
Thanks for this post and the code.
Trying to implement your methods
Is it possible for someone with a VERY basic grasp of PHP to replicate your methods from this article? Does the code go in template.php or in a custom module? And when you say:
'As such, our new HTML email template went into a function named phptemplate_simplenews_newsletter_body().'
I presume there is a whole lot of code there which you didn't post, and earlier you mention 'with some additional work'. I realise this blog is meant for more experienced programmers but it is the only place I've found a solution to the HTML email newsletter nightmare in Drupal/simplenews.
Thanks though.
Hey Ssteve, Most of the
Hey Ssteve,
Most of the above code went into a custom module named os_newsletter. You can create your own fairly easily (even with a limited grasp of PHP) using this module developer's guide.
As far as the template function (which was placed in template.php), since our newsletter is quite complex, you're right, there is quite a bit of code in there. However, it doesn't have to be. The template could be as simple as:
preview function
Preview is a nice function for simplenews indeed. However it can not work when a newsletter is send via mime mail and html emails are exactly the thing for which use for a preview will be used. But I'm open for suggestions.
Jonathan, nice solution for a simple html newsletter.
email-standards.org
There is an interesting survey of various MUA capabilities here:
http://www.email-standards.org/
What's most surprising is that GMail has the lowest ranking! Hopefully someday CSS support will improve, and constructing these emails will get easier.
Body part
Hello,
Thanks for this great article.
A significant part is not working for me. The body part is gone in both the preview and the sent mail.
Any ideas? I'm using Simplenews 6.x-1.0-rc6
Fred, I haven't had a chance
Fred,
I haven't had a chance to try this with the later versions of Simplenews, but I know that the module is undergoing drastic changes with every release, so it isn't surprising that the above doesn't work properly. I'll either post back here, or create a new article when I have a chance to work with a more recent version.
Thanks...
...for the quick response!
Drupal 5
Any chance to migrate this script to drupal 5?
Another problem
I tried to put images and tried out to use simple filter (no line breaks) and the images are encoded like this
and i wanted to send absolute references (Url)
$body and $title not showing up
Theoretically, I love this post. It worked for 3 weeks and I was getting closer to perfection for my email newsletter, but my site stopped sending any emails. SMTP module was installed and magically the emails started working again (although I had to replace my template.php and repaste the code for the $body to print, so it had some issues being recognized, but I got it to work even though it declared some error in the code). It worked for 3 days then stopped sending emails again. I've got the email working by using the smtp debug (yeah!), but now the template.php code isn't recognized to print the $title and $body so only the footer message gets sent. What am I doing wrong? (I'm on Drupal 6.11).
This is the code that worked for 3 weeks and 3 days (now it isn't being recognized at all in template.php):
function phptemplate_simplenews_newsletter_body($body, $title, $language) {
// alter the following how you wish:
$output = ''. $title ."\n";
$output .= '' . $body . '';
return $output;
}
Thanks for your help.
Holly, I guess that's
Holly, I guess that's because of the changes in Simplenews - the latest version (rc6) uses template and preprocess function instead of theming functions (see line 2332 of the simplenews.module). You can try placing simplenews-newsletter-body.tpl.php in your theme directory and customize it. Also take a look at the instructions in the simplenews-newsletter-body.tpl.php included with the module.
Creating HTML Newsletter
Hi Joshua,
I'm Lau from Malaysia. Very interested with your posts. However, I'm still new to drupal and php and I don't have any basic on php yet. Is there any easiest way to do this? For example on open which file and adding new lines?
I'm so sorry for troubling you. I wish I could try this but I don't know where to start.
Hope to hear from you soon. Cheers!
In-line text link display issue
Hi there, I've posted this in the Drupal forums as well, but figured I'd check here as well.
I'm pretty sure this has something to do with either the MIME type settings or the HTML filter settings, probably a simple fix, but it's quite irritating, and I'm hoping someone can help me out here...
Basically, I installed Simplenews and the Mime Mail modules for a standard newsletter. Everything is working perfectly, *except* that in HTML messages, in-line text links keep showing up with the link *next* to the text.
For instance, if it's entered as:
<a href="http://www.domain.com">This is a link</a>...it shows up properly in Drupal, but in the received email it shows up as:
This is a link <http://www.brainwrap.com/>Any assistance would be greatly appreciated. I've tried setting the input format to both Filtered HTML and Full to no avail.
Need exactly the same for drupal 5
Hi,
Really gr8 post!!
But I need exactly the same for drupal 5. How can i do that. Tried several modules but seems nothing worked for me. Plz help!!
Preview
Hello there,
I'm trying to implement the Preview HTML Format functionality but I can't get it to work.
I've tested each line of code within the build_preview function and I think the problem is coming from its last line ($form_state['node_preview'] = theme('simplenews_newsletter_body', $cloned_node->body, check_plain($cloned_node->title), '')).
When I click on the Preview HTML Format button, I'm sent back to the Create Newsletter issue but with an empty form.
Oh by the way, I'm using the last Drupal 6.
Thank you very much for your help! Regards,
David