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.

UPDATEs:

Screenshots of before and after

please host this last image on your own website… i can't guarantee the imgshare link will last.

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 364) 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 three 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 8775) 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",true).'">'.
					$id.' '.strftime($conf['dformat']).'</a>';
	$right		=	'<a href="'.wl($id,'',true).'">'.
					$id.' '.strftime($conf['dformat'],@filemtime(wikiFN($id))).'</a> ('.
					$lang['current'] . ')';
 
	$tdf 		=	 new TableDiffFormatter();
 
	$diffHTML 	=	"<html>\n<body>\n<h1 style=\"font-size: xx-large;\"><a href=\"".wl($id,'',true)."\"><font color=\"#FF6600\">".$id.
					"</font></a> 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

Then intercept the mailing action and generate a HTML-formatted version of the notification on new page creation. Locate the following code

    $diff = rawWiki($id);

in the notify() function of inc/common.php and insert the following code right after it:

/***********************************
 * Generate HTML Notification Hack (Part 2)
 *
 * inc/common.php
 * By Berteh (berteh [at] hotmail [dot] com)
 *
 ***********************************/
	  $diffHTML 	=	"<html>\n<body>\n<h1 style=\"font-size: xx-large;\"><a href=\"".wl($id,'',true)."\"><font color=\"#FF6600\">".$id.
					"</font></a> was just added</h1>\n<h2 style=\"font-size: large;\">by <font color=\"#999999\"><b>".
					$_SERVER['REMOTE_USER']."</b></font> on ".strftime($conf['dformat'])."</h2><br />\n".p_wiki_xhtml($id).
					"\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>";
/***********************************
 * End Generate HTML Notification Hack (Part 2)
 ***********************************/

Part 3

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,$conf['mailfrom'],'',$bcc);

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

/***********************************
 * Generate HTML Notification Hack (Part 3)
 *
 * inc/common.php
 * By Lin Junjie (mail [dot] junjie [at] gmail [dot] com)
 *
 ***********************************/
  if ($diffHTML) {
  	mail_send_html($to,$subject,$text,$diffHTML,$conf['mailfrom'],'',$bcc);
  }else {
  	mail_send($to,$subject,$text,$conf['mailfrom'],'',$bcc);
  }
/***********************************
 * End Generate HTML Notification Hack (Part 3)
 ***********************************/  

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

If you want to show the mail of the user that made the change as mail sender rather than a no-reply address use

  $sendermail = $INFO['userinfo']['name']. ' <'.$INFO['userinfo']['mail'].'>';
  if ($diffHTML) {
        mail_send_html($to,$subject,$text,$diffHTML,$sendermail,'',$bcc);
  }else {
        mail_send($to,$subject,$text,$sendermail,'',$bcc);
  }

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 integrating this into a plugin, please do so and let us know here!

history

Questions and problems

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)
Line numbers are given based on this version.
3)
tested and working with DokuWiki 2008-05-05 & 2009-12-25c, but line numbers don't match the hack explanation, feel free to correct.
4)
Line 67 of Rincewind
5)
1148 Rincewind