Email Addresses on Custom Module, add programmatically

I have a custom module to which I added Email Addresses.

The Email Addresses fields appear correctly in the record view, I can edit them and I can save email addresses with the primary, invalid and opt-out flags. 

So far so good.

When I try to process and import records via code (a one-off entry point) I can't seem to add the email addresses programmatically. Eventually I will need an API to add records so this is essential to operations.

This script executes without issue. The records are added, the email validation check passes, but the email addresses are not saved.

<?php
global $db;
$q = 'select * from str_sample_users';
$result=$db->query($q);
while($item=$db->fetchByAssoc($result)){
  $widBean = BeanFactory::newBean('wid_WolfID');
  $widBean->wolfid = $item['username'];
  $widBean->name = $item['firstname'].' '.$item['lastname']. ' - ' . $item['email'];
  $widBean->reg_date = $item['regdate'];
  $widBean->save();

  $wid = BeanFactory::retrieveBean('wid_WolfID', $widBean->id);
  if(!empty($wid) && $wid->emailAddress->isValidEmail($item['email'])){
    $GLOBALS['log']->fatal("validated " . $item['email']);
    $wid->emailAddress->addAddress($item['email'],true);
  }
  $wid->save();
}

I assume I'm missing something in the save() for the bean, but I'm not sure what.

I looked at Contacts and Leads but I can't quite see where I'm going wrong.

The emailAddress is in the bean, in this case it's a pre-existing address:

   [emailAddress] => EmailAddress Object
        (
            [disable_row_level_security] => 1
            [table_name] => email_addresses
            [module_name] => EmailAddresses
            [module_dir] => EmailAddresses
            [object_name] => EmailAddress
            [disable_custom_fields] => 1
            [smarty] =>
            [addresses] => Array
                (
                    [0] => Array
                        (
                            [email_address] => 1234this@outlook.com
                            [primary_address] => 1
                            [reply_to_address] =>
                            [invalid_email] =>
                            [opt_out] =>
                            [email_address_id] => b87f2f16-4430-11e9-8fee-001a4a160170
                        )

                )

            [hasFetched] =>
            [view] =>
            [email_address] =>
            [dontLegacySave] =>
            [opt_out] =>
            [invalid_email] => 0
            [fetchedAddresses] => Array
                (
                )

            [db] => MysqliManager Object
                (
                    [dbType] => mysql
                    [variant] => mysqli
                    [priority] => 10
<..snip..>

Any thoughts?

thank you,

FrancescaS

  • Maybe the code may looks like that:

      $widBean->reg_date = $item['regdate'];

      if($wid->emailAddress->isValidEmail($item['email'])){
          
    $widBean->email1 = $item['email'];
      }
      $widBean->save();

    Regards

    André Lopes
    Lampada Global
    Skype: andre.lampada
  • Thank your for update on deprecated email1.

    By looking at the method "addAddress" it is possible that the incoming e-mail address already exists. Double check sugarcrm.log. Hopefully you will see the error:

    SUGAREMAILADDRESS: Existing primary address could not be overriden [ {$addr} ]

    Additionally, the method "isValidEmail" is static, so if may throw some exception somehow, and indeed the method "addAddress" validates the incoming e-mail address by default unless you decide do don't do it, and sugarcrm.log may have the following record if it is an invalid e-mail:

    SUGAREMAILADDRESS: email address is not valid [ {$addr} ]

    Regards

    André Lopes
    Lampada Global
    Skype: andre.lampada
  • All the logs are clear. There are no errors or warnings.

    Even if the email existed already, I should be able to relate it to the wid bean as primary. For example, if you have a Contact with a given email address you can still use the add method to add that same address to a Lead. 

    The add is executing correctly, when I look at $widBean after the 

    $wid->emailAddress->addAddress($item['email'],true);

    I can see the address correctly defined in the bean:

      [emailAddress] => EmailAddress Object
            (
                [disable_row_level_security] => 1
                [table_name] => email_addresses
                [module_name] => EmailAddresses
                [module_dir] => EmailAddresses
                [object_name] => EmailAddress
                [disable_custom_fields] => 1
                [smarty] =>
                [addresses] => Array
                    (
                        [0] => Array
                            (
                                [email_address] => 1234this@outlook.com
                                [primary_address] => 1
                                [reply_to_address] =>
                                [invalid_email] =>
                                [opt_out] =>
                                [email_address_id] => b87f2f16-4430-11e9-8fee-001a4a160170
                            )

                    )

                [hasFetched] =>
                [view] =>
                [email_address] =>
                [dontLegacySave] =>
                [opt_out] =>
                [invalid_email] => 0
                [fetchedAddresses] => Array
                    (
                    )

                [db] => MysqliManager Object
                    (
                        [dbType] => mysql
                        [variant] => mysqli
                        [priority] => 10
    <..snip..>

    The problem seems to be that it's not saving it. I think there is something missing in my custom wid_WolfID Bean to save the email address.

    These are my vardefs which I based on what I found in Contacts/Leads and which seem to work considering I can add addresses via the interface.

    <?php
    $dictionary["wid_WolfID"]['fields']['email'] =
        array (
          'name' => 'email',
          'type' => 'email',
          'query_type' => 'default',
          'source' => 'non-db',
          'operator' => 'subquery',
          'subquery' => 'SELECT eabr.bean_id FROM email_addr_bean_rel eabr JOIN email_addresses ea ON (ea.id = eabr.email_address_id) WHERE eabr.deleted=0 AND ea.email_address LIKE',
          'db_field' =>
          array (
            0 => 'id',
          ),
          'vname' => 'LBL_EMAIL_ADDRESS',
          'studio' =>
          array (
            'visible' => true,
            'searchview' => true,
            'editview' => true,
            'editField' => true,
          ),
          'duplicate_on_record_copy' => 'always',
          'len' => 100,
          'link' => 'email_addresses_primary',
          'rname' => 'email_address',
          'module' => 'EmailAddresses',
          'full_text_search' =>
          array (
            'enabled' => true,
            'searchable' => true,
            'boost' => 1.9499999999999999555910790149937383830547332763671875,
          ),
          'audited' => true,
          'pii' => true,
        );

    $dictionary["wid_WolfID"]['fields']['invalid_email'] =
        array (
          'name' => 'invalid_email',
          'vname' => 'LBL_INVALID_EMAIL',
          'source' => 'non-db',
          'type' => 'bool',
          'link' => 'email_addresses_primary',
          'rname' => 'invalid_email',
          'massupdate' => false,
          'studio' => 'false',
          'duplicate_on_record_copy' => 'always',
        );
    $dictionary["wid_WolfID"]['fields']['email_opt_out'] =
        array (
          'name' => 'email_opt_out',
          'vname' => 'LBL_EMAIL_OPT_OUT',
          'source' => 'non-db',
          'type' => 'bool',
          'link' => 'email_addresses_primary',
          'rname' => 'opt_out',
          'massupdate' => false,
          'studio' => 'false',
          'duplicate_on_record_copy' => 'always',
        );
    $dictionary["wid_WolfID"]['fields']['email_addresses_primary'] =
        array (
          'name' => 'email_addresses_primary',
          'type' => 'link',
          'relationship' => 'wid_wolfid_email_addresses_primary',
          'source' => 'non-db',
          'vname' => 'LBL_EMAIL_ADDRESS_PRIMARY',
          'duplicate_merge' => 'disabled',
          'primary_only' => true,
        );
    $GLOBALS["dictionary"]["wid_WolfID"]['fields']['email_addresses'] =
        array (
          'name' => 'email_addresses',
          'type' => 'link',
          'relationship' => 'wid_wolfid_email_addresses',
          'source' => 'non-db',
          'vname' => 'LBL_EMAIL_ADDRESSES',
          'reportable' => false,
          'unified_search' => true,
          'rel_fields' =>
          array (
            'primary_address' =>
            array (
              'type' => 'bool',
            ),
          ),
        );
    $GLOBALS["dictionary"]["wid_WolfID"]['fields']['email_addresses_non_primary'] =
        array (
          'name' => 'email_addresses_non_primary',
          'type' => 'varchar',
          'source' => 'non-db',
          'vname' => 'LBL_EMAIL_NON_PRIMARY',
          'studio' => false,
          'reportable' => false,
          'massupdate' => false,
        );
    $GLOBALS["dictionary"]["wid_WolfID"]['relationships']['wid_wolfid_email_addresses'] =
        array (
          'lhs_module' => 'wid_WolfID',
          'lhs_table' => 'wid_wolfid',
          'lhs_key' => 'id',
          'rhs_module' => 'EmailAddresses',
          'rhs_table' => 'email_addresses',
          'rhs_key' => 'id',
          'relationship_type' => 'many-to-many',
          'join_table' => 'email_addr_bean_rel',
          'join_key_lhs' => 'bean_id',
          'join_key_rhs' => 'email_address_id',
          'relationship_role_column' => 'bean_module',
          'relationship_role_column_value' => 'wid_WolfID',
        );
    $GLOBALS["dictionary"]["wid_WolfID"]['relationships']['wid_wolfid_email_addresses_primary'] =
        array (
          'lhs_module' => 'wid_WolfID',
          'lhs_table' => 'wid_wolfid',
          'lhs_key' => 'id',
          'rhs_module' => 'EmailAddresses',
          'rhs_table' => 'email_addresses',
          'rhs_key' => 'id',
          'relationship_type' => 'many-to-many',
          'join_table' => 'email_addr_bean_rel',
          'join_key_lhs' => 'bean_id',
          'join_key_rhs' => 'email_address_id',
          'relationship_role_column' => 'bean_module',
          'relationship_role_column_value' => 'wid_WolfID',
          'primary_flag_column' => 'primary_address',
        );
    $GLOBALS["dictionary"]["wid_WolfID"]['templates']['email_address']='email_address';
    ?>

                                                                                                                                             

    I also added the emailAddress method to the wid_WolfID bean I needed for the email address validation and the email address add methods to be known to the bean.

    require_once('modules/wid_WolfID/wid_WolfID_sugar.php');
    class wid_WolfID extends wid_WolfID_sugar {
      public function __construct() {
        parent::__construct();
        $this->emailAddress = BeanFactory::newBean('EmailAddresses');
      }

    }

    FrancescaS

  • Matt Marum,

    is there any documentation on how to add Email Addresses to a custom module?

    I've not been able to find anything specific to v7.x and higher.

    thank you,

    FrancescaS

  • Hi Francesca Shiekh,

    We could make use of ready-made vardefs templates available inside include/SugarObjects/implements.

    We need to add this entry under 'uses' array in module vardefs. For eg:

    $dictionary['<custom_module>']['uses'] = array('email_address');

    //create email fields
    VardefManager::createVardef("<custom_module_bean_name>", "<custom_module_bean_class>", array('email_address'));

    For reference, you can check out Accounts or Contacts module vardefs in cache/modules/Accounts/Accountvardefs.php

    Let us know if this works.

    Regards.

  • Thank you hats!

    The Vardef suggestion saves a ton of double checking! I had looked at the Contact and Leads vardefs to generate my own but that makes it so much easier and works like a charm.

    Unfortunately it does not solve my problem of 

    $wid->emailAddress->addAddress($item['email'],true);

    not actually saving the address.

    FrancescaS

  • Hi Francesca Shiekh,

    Sorry, I just overlooked your original problem. Usually, we use SugarEmailAddress class to save email addresses related to a particular bean record. Eg as follows:

    $sea = new SugarEmailAddress;
    $sea->addAddress('test@test.com', true); 
    $sea->save($bean->id, $bean->module_dir);

     

    Alternatively, you can also use your custom bean to save an email address. Eg as follows:

    $bean->emailAddress->addAddress('test@test.com',true);
    $bean->emailAddress->save($bean->id, $bean->module_dir);

     

    where $bean is the bean of your custom module

     

    Your script misses the save call to email address bean. Please give it a try and let us know if it works.

    Regards.

  • Thank you hats,

    The problem is that in my custom module, if I add email addresses to a record via the interface using inline edit on record view or the edit view it works just fine. The address is saved and related to my custom record via the email_addr_bean_rel table entry. No problems there

    But if I try to import a number of records via spreadsheet, though it recognizes email addresses, and shows me the correct field mapping, the addresses won't import. The import will complete, all the other fields are populated, but the email addresses are not saved to the email_addresses table, and don't exist in email_addr_bean_rel.

    All the logs are clean and there is no indication of why they were not imported.

    If I try to import via code, reading in the fields and creating the bean, and use 

    $bean->emailAddress->addAddress('test@test.com',true); as you suggested I have the same problem, no email addresses are saved.

    I just tried your other suggestion:

    $bean->emailAddress->save($bean->id, $bean->module_dir);

     

    The same thing happens. No email addresses are saved.

    I checked all the logs and there are no errors anywhere.

  • Sorry to hear that it is still not working.

    I personally use SugarEmailAddress class for email manipulation within a bean.

    $sea = new SugarEmailAddress;
    $sea->addAddress('test@test.com', true); 
    $sea->save($bean->id, $bean->module_dir);

    Would you please give this a try?