Table of Contents

Better Email Notifications with HTML formatting

This hack was in part inspired by the beautiful page change notifications sent out by other wiki software such as PBWiki, which uses HTML formatting instead of plain-text, and in part inspired by the existing diff rendering system in DokuWiki. I figured if DokuWiki is already capable of generating nicely formatted diff of page changes, I could tap into the system to send out HTML-formatted page notifications.

UPDATE: Instructions updated for DokuWiki 2008-04-11 RC2.

Screenshots of before and after

What you need

Applying the hack

inc/mail.php

First, we need to create a new function that can handle our HTML e-mails. We'll do so by creating one based on mail_send() in mail.php. Open up the file and locate the mail_send() function

function mail_send($to, $subject, $body, $from='', $cc='', $bcc='', $headers=null, $params=null){

at line 36 of an unmodified mail.php. Insert the following code just above the mail_send() function.

/***********************************
 * HTML Mail functions
 *
 * Sends HTML-formatted mail
 * By Lin Junjie (mail [dot] junjie [at] gmail [dot] com)
 *
 ***********************************/
function mail_send_html($to, $subject, $body, $bodyhtml, $from='', $cc='', $bcc='', $headers=null, $params=null){
  if(defined('MAILHEADER_ASCIIONLY')){
    $subject = utf8_deaccent($subject);
    $subject = utf8_strip($subject);
  }
 
  if(!utf8_isASCII($subject)) {
    $subject = '=?UTF-8?Q?'.mail_quotedprintable_encode($subject,0).'?=';
    // Spaces must be encoded according to rfc2047. Use the "_" shorthand
    $subject = preg_replace('/ /', '_', $subject);
  }
 
  $header  = '';
 
  $usenames = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? false : true;
 
  $random_hash = md5(date('r', time())); // added
 
  $to = mail_encode_address($to,'',$usenames);
  $header .= mail_encode_address($from,'From');
  $header .= mail_encode_address($cc,'Cc');
  $header .= mail_encode_address($bcc,'Bcc');
  $header .= 'MIME-Version: 1.0'.MAILHEADER_EOL;
  $header .= "Content-Type: multipart/alternative; boundary=PHP-alt-".$random_hash.MAILHEADER_EOL;
  $header .= $headers;
  $header  = trim($header);
 
  $body = mail_quotedprintable_encode($body);
  $bodyhtml = mail_quotedprintable_encode($bodyhtml);
 
  $message =	"--PHP-alt-".$random_hash."\r\n".
				"Content-Type: text/plain; charset=UTF-8"."\r\n".
				"Content-Transfer-Encoding: quoted-printable"."\r\n\r\n".
				$body."\r\n\r\n".
				"--PHP-alt-".$random_hash."\r\n".
				"Content-Type: text/html; charset=UTF-8"."\r\n".
				"Content-Transfer-Encoding: quoted-printable"."\r\n\r\n".
				$bodyhtml."\r\n".
				"--PHP-alt-".$random_hash."--";
 
  if($params == null){
    return @mail($to,$subject,$message,$header);
  }else{
    return @mail($to,$subject,$message,$header,$params);
  }
}

The function has the added advantage of sending along the standard plain-text version for mail clients that cannot display HTML formatting. That's all for mail.php.

inc/common.php

There are two parts of hack to apply to common.php.

Part 1

First, we need to intercept the mailing action and generate a HTML-formatted version of the notification. Locate the following code

    $diff    = $dformat->format($df);

in the notify() function at line 877 of an unmodified common.php and insert the following code right after it:

/***********************************
 * Generate HTML Notification Hack (Part 1)
 *
 * inc/common.php
 * By Lin Junjie (mail [dot] junjie [at] gmail [dot] com)
 *
 ***********************************/
 
	$df  		=	new Diff(explode("\n",htmlspecialchars(rawWiki($id,$rev))),
					explode("\n",htmlspecialchars(rawWiki($id,''))));
	$left		=	'<a href="'.wl($id,"rev=$rev").'">'.
					$id.' '.strftime($conf['dformat']).'</a>';
	$right		=	'<a href="'.wl($id).'">'.
					$id.' '.strftime($conf['dformat'],@filemtime(wikiFN($id))).'</a> ('.
					$lang['current'] . ')';
 
	$tdf 		=	 new TableDiffFormatter();
 
	$diffHTML 	=	"<html>\n<body>\n<h1 style=\"font-size: xx-large;\"><font color=\"#FF6600\">".$id.
					"</font> was just edited</h1>\n<h2 style=\"font-size: large;\">by <font color=\"#999999\"><b>".
					$_SERVER['REMOTE_USER']."</b></font> on ".strftime($conf['dformat'])."</h2><br />\n"."<table ".
					"width=600 style=\"font-family: courier new; font-size:medium;\">\n<tr>\n<th colspan=\"2\" ".
					"width=\"50%\" style=\"border-bottom: 1px solid #333333; font-weight: bold; text-align: left;\">\n".
					$left."\n</th>\n<th colspan=\"2\" width=\"50%\" style=\"border-bottom: 1px solid #333333; ".
					"font-weight: bold; text-align: left;\">".$right."</th>\n</tr>".$tdf->format($df).
					"</table>\n"."<br />\n<p style=\"font-size: medium;\">---<br />\nThis mail was ".
					"automatically generated by DokuWiki at<br/>\n<a href=\"".DOKU_URL."\">".DOKU_URL."</a></p>\n".
					"</body>\n</html>";
 
	$diffHTML	=	str_replace('class="diff-blockheader"','style="font-weight: bold; font-family: courier new;"',$diffHTML);
	$diffHTML 	=	str_replace('class="diff-addedline"','style="background-color: #ddffdd; font-family: courier new;"',$diffHTML);
	$diffHTML 	=	str_replace('class="diff-deletedline"','style="background-color: #ffffbb; font-family: courier new;"',$diffHTML);
	$diffHTML 	=	str_replace('class="diff-context"','style="background-color: #f5f5f5; font-family: courier new;"',$diffHTML);	
	$diffHTML 	=	str_replace('class="diffchange"','style="color: red;"',$diffHTML);
	$diffHTML 	=	str_replace('<strong>','<strong><font color="#FF0000">',$diffHTML);
	$diffHTML 	=	str_replace('</strong>','</font></strong>',$diffHTML);
	$diffHTML 	=	str_replace('<td>','<td style="font-family: courier new;">',$diffHTML);
 
/***********************************
 * End Generate HTML Notification Hack (Part 1)
 ***********************************/

Part 2

Next, we will need to call our mail_send_html() function to send out the HTML-formatted email that we have generated. Locate the following code

  mail_send($to,$subject,$text,$from,'',$bcc);

right before the notify() function ends. REPLACE this line of code with the following code:

/***********************************
 * Generate HTML Notification Hack (Part 2)
 *
 * inc/common.php
 * By Lin Junjie (mail [dot] junjie [at] gmail [dot] com)
 *
 ***********************************/
  if ($diffHTML) {
  	mail_send_html($to,$subject,$text,$diffHTML,$_SERVER['REMOTE_USER']. ' <donotreply@INSERT-YOUR-SERVER-HERE.com>','',$bcc);
  }else {
  	mail_send($to,$subject,$text,$_SERVER['REMOTE_USER']. ' <donotreply@INSERT-YOUR-SERVER-HERE.com>','',$bcc);
  }
/***********************************
 * End Generate HTML Notification Hack (Part 2)
 ***********************************/

Note that part 2 of the hack has the added functionality of changing the sender of the mail to the name of the user that made the change.3) Do replace the two instances of “INSERT-YOUR-SERVER-HERE.com” with your own server.

That's all folks

That's it! We're done! Leave a message here or contact me at mail [dot] junjie [at] gmail [dot] com. If you have any way of intergrating this into a plugin, please do so and let us know here!

DEVEL: IMPROVEMENT

Probably you should use absolute links in the wl( .. ,.., true); function, otherwise sending relative links in html documents won't work properly ;).

1) I used TextWrangler on the Mac. You should probably use Wordpad if you're on Windows because Notepad doesn't understand the Unix style line endings.
2) Other versions could work, but I have only tested this with the latest versions. Line numbers are given based on this version.