PHP: How to append Google Analytics’ campaign parameters to all your emails at once?

Using Google Analytics for tracking your users’ behavior is almost like using Air for breathing, then it comes its Custom Campaigns feature that will help you identify which of your marketing methods are more effective, or which campaigns emails gives you the better traffic, and so on.

But, how could I append the custom campaign url parameters to all my emails at once? .. Or what if I want to know which of my transactional emails (notifications, invitations … ) is better in retaining users, how could I append a parameter containing email template’s name to all links in the email? & how to do it in a smart way?

Answer #1 (the dumbest answer, but working!)
Just go through every single link in your email templates & append your campaign parameters or template’s name referral. Not only this will cost you time & effort, but also you will bang your head against the wall when you try to change it later!

Answer #2 (not recommended)
Be lazy & use Regex to process the final email’s html (just before sending) & append whatever you like to all the links in it. You can use the one from this answer, or even this one, or even come up with your own super enhanced regex to do the job, it is up to you.

Answer #3 (recommended)
Why reinvent the wheel by doing your own Regex while you can use an official Dom parser of your choice, since I’m using PHP, then it comes to the awesome DOMDocument class & its pretty effective loadHTML() function & here comes the awesomeness (thx to this answer by Wrikken which I edited after trying it for real):

* appending campaign parameters to every single link `<a href=''></a>`
* in the given $bodyHtml
* @param type $bodyHtml
public function appendCampaignPrameters($bodyHtml, $utmCampaign) {
$newParams = [
'utm_source' => 'email',
'utm_medium' => 'email',
'utm_campaign' => $utmCampaign
$doc = new \DOMDocument();
$internalErrors = libxml_use_internal_errors(true); //
foreach ($doc->getElementsByTagName('a') as $link) {
$url = parse_url($link->getAttribute('href'));
$gets = $newParams;
if (isset($url['query'])) {
$query = [];
parse_str($url['query'], $query);
$gets = array_merge($query, $newParams);
$newHref = '';
if (isset($url['scheme'])) {
$newHref .= $url['scheme'] . '://';
if (isset($url['host'])) {
$newHref .= $url['host'];
if (isset($url['port'])) {
$newHref .= ':' . $url['port'];
if (isset($url['path'])) {
$newHref .= $url['path'];
$newHref .= '?' . http_build_query($gets);
if (isset($url['fragment'])) {
$newHref .= '#' . $url['fragment'];
$link->setAttribute('href', $newHref);
return $doc->saveHTML();

Why Answer #3 is the recommended one?
Using a regex to parse only the links from the html’s string, seems a lot faster than parsing the whole dom elements, but does speed difference really matters when regex could give you incorrect results?! .. are you really willing to sacrifice speed for correctness?
I don’t really think so! .. In this, I’ll go with Gary Pendergast‘s opinion that we shouldn’t use Regex, but we should use the Dom parsing libraries which are well tested in terms of speed & correctness.

Hope you have found what you were looking for ๐Ÿ™‚ , & thx for sharing it with more people who may need it too.