Is it possible to alter the mailing form? I want to set the default value for url_tracking to false. Usually I would write a hook_civicrm_buildForm and set a custom default value but this hook is not being called when loading the mailing form.

  • 1
    The mailing page/form is built with angular, I'm not sure if there's a way to hook into angular, there's a hook_civicrm_AngularModules in the hook reference, that said I guess you'll have to go with JavaScript/jQuery or modify the angular partial at /path/to/civi/civicrm/civicrm/ang/crmMailing/BlockTracking.html adding ng-init="mailing.url_tracking='0'" to the url_tracking input, that will make the checkbox unchecked when the page loads, please note that this is not recommended, you will lose any changes made to those files when upgrading CiviCRM.
    – Andrei
    Commented Jan 23, 2016 at 12:00
  • I would update the initial value on document ready via JS in my theme. But I can't find a way to check, if the input has already been "touched". I don't want to uncheck the input if the user has set it by himself. Commented Jan 25, 2016 at 16:08

6 Answers 6


Disclaimer: I'm not an angularjs expert

Again this is a bit of a hack, we are intercepting a built-in CiviCRM angular directive and extending to add behaviour.

Create a custom extensions or use an existing one and implement hook_civicrm_angularModules:

function myextension_civicrm_angularModules(&$angularModules){
        $angularModules['myModule'] = array(
                'ext' => 'myextension',
                'js' => array('js/myModule.js'),

In your js file:

// js/myModule.js

(function(angular, $, _){
  // Your module
  angular.module('myModule', []);

  // the hack

    // crmMailingBlockTracking directive
    $provide.decorator('crmMailingBlockTrackingDirective', function($delegate){
        var directive = $delegate[0];

        // Original link function
        var link = directive.link;

        // compile function, returns new link function
        directive.compile = function(){
            return function(scope, element, attrs){
                // get old link functionality
                link.apply(this, arguments);

                // new functionality here
                scope.$parent.$watch(attrs.crmMailing, function(){
                    var createdDate = new Date(scope.mailing.created_date).getTime()/1000;
                    var nowDate = new Date().getTime()/1000;

                    if((nowDate - createdDate) < 60){
                        scope.mailing.url_tracking = '0';
                        CRM.alert('Tracking Disabled');


        return $delegate;
})(angular, CRM.$, CRM._);

The angular Mailing app uses a kind of boilerplate service, crmMailingSimpleDirective for constructing directives see here more info

The above snippet will do the same as my other answer without relying on setTimeout().

Hope that helps.

  • That's great, thank you! Folks can also set "Track Opens" to no by default, by using scope.mailing.open_tracking = '0'; instead of or in addition to scope.mailing.url_tracking = '0'; in the js file.
    – Norris
    Commented Aug 10, 2017 at 0:27

I guess this is not the best way to do it and perhaps someone can point you to a better solution. I'll put it as an answer for readability purposes.


Create a custom extensions or use an exiting and implement hook_civicrm_pageRun, something like:

function myextension_civicrm_pageRun(&$page){
  $pageName = $page->getVar('_name');
  if ($pageName == 'Civi\Angular\Page\Main') {
    CRM_Core_Resources::singleton()->addScriptFile('myextension', 'js/myJsScript.js');

Edit: making some assumption this is with what I came up, as I said not the best thing to do but... perhaps someone finds it useful.

// js/myJsScript.js


  var disableUrlTracking = function(){
    // Access angular $scope
    var mailingElement = document.querySelector('[ng-model="mailing.url_tracking"]');
    var mailingScope = angular.element(mailingElement).scope();

    // Convert the mailing created date into seconds
    var createdDate = new Date(mailingScope.mailing.created_date).getTime()/1000;

    // Current date into seconds
    var nowDate = new Date().getTime()/1000;

    // Compare both dates
    var dif = nowDate - createdDate;

      // if the difference is less 60 seconds, assuming that to creat a mailing takes more than 60 seconds
    if(dif <= 60){
      mailingScope.mailing.url_tracking = '0';
      CRM.alert('URL Tracking disabled', 'URL Tracking');
  // Optional: wait for the page to load completeley, in my case it takes some seconds until it renders the whole mailing page.
  // If you don't have that issue just call the function
  setTimeout(disableUrlTracking, 4000 );

  • But if the user enables url_tracking and saves the mailing as draft to finish it later, your code will disable it, when the user opens the page again. Commented Jan 26, 2016 at 8:03
  • Totally true, I haven't thought about that, my fault, I misunderstood your comment.
    – Andrei
    Commented Jan 26, 2016 at 8:09
  • Updated the answer, maybe you can find a better way to check if the mailing has been saved as a draft
    – Andrei
    Commented Jan 26, 2016 at 15:01
  • sorry that I've not accepted your answer. I'm still hoping that there might be an easy way to alter the form. Commented Apr 27, 2016 at 13:15
  • No worries, I agree there must be a better way to do it, at least it should, perhaps the angular way, but better doesn't necessarily mean easier, have a look at the Api explorer and try a get action on the Mailing entity, the only way I see you could differentiate a saved draft from a new mailing is comparing the created_date with the current date that is being edited, as there's no other property that I can think of that you could check for, for a sent/scheduled mailing you can see that you do have new properties like, is_completed, scheduled_date, scheduled_id, etc
    – Andrei
    Commented Apr 28, 2016 at 0:01

In Drupal you can do this with hook_civicrm_pre():

function mymodule_civicrm_pre($op, $objectName, $id, &$params) {
  if ($objectName == 'Mailing' && $op == 'create') {
    $params['url_tracking'] = 0;
  • It seems this is the only answer that works with Mosaico. In Mosaico the email message is immediately saved before you can get to the Tracking tab. So, the angular/javascript based solutions are not executed until you click on the Tracking tab. But if you remember to click on the tracking tab, you don't really need this functionality. So, better turn it off on creation, and leave open the possibility of turning it back on when updated.
    – Jamie
    Commented Sep 28, 2021 at 19:08

Another option you may want to consider is installing CiviProxy. You set it up somewhere on the public Internet (I imagine a free hosting account would suffice), whitelist its IP in your firewall, and it has a very limited ability to talk to CiviCRM. But the CiviProxy extension will rewrite your URL tracking to go to the proxy - and the proxy knows how to handle the rewrite. It also lets you, e.g. embed images in your mailing, which otherwise wouldn't be possible.


I wrote an extension borrowing heavily from @andrei, with a few improvements on identifying a creation vs modification of a draft

Hope you find it useful



This feature is now part of core: Administer -> CiviMail -> CiviMail Component Settings:

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.