This is how i am approaching to trigger

trigger UpdateAccountEmails on Contact (after update){  
    //extract all contact Ids for use in query
    contact all_contact = [select id,name,email from contact];
    Set<Id> contactIds = new Set<Id>();
    for(Contact c : Trigger.new){
        if(trigger.oldMap.get(c.Id).Email != c.Email){//email has been changed

    List<Account> accounts = new List<Account>();
    for(Contact c : [SELECT Id, Account.Id, Account.Custom_Email__c FROM Contact WHERE Id IN :contactIds]){
        //assign the new email
        c.recordPageCont.Custom_Email__c = Trigger.newMap.get(c.Id).Email;
        //extract the account into our list

    update accounts;

An Account has many Contacts so there is a logical problem: the Account will just show the email from the last Contact updated.

But accepting that, this trigger should do the job:

trigger UpdateAccountEmails on Contact (after update) {
    Map<Id, Account> m = new Map<Id, Account>();
    for(Contact c : Trigger.new){
        if (Trigger.oldMap.get(c.Id).Email != c.Email) {
            m.put(c.AccountId, new Account(Id = c.AccountId, Custom_Email__c = c.Email));
    update m.values();

Using the map ensures that only one Account update is done even if many Contacts from the same Account are being updated.

When updating an object that you already have an ID for there is no need to query (unless you want to also check if there is a change to the value).


Contacts will be updated for many reasons, not just for email address changes. Your trigger needs to be aware of that and only fire when the email address has changed. You also don't want to be querying ALL email addresses for ALL of your contacts, only the ones that have changed.

However, as you'll see, you don't even need to run that query because trigger.old will contain the previous email address making it unnecessary. Your trigger should look more like the following:

trigger UpdateAccountEmails on Contact (after update){  

set<contact>con2up = new set<contact>();
map<Id,string>con2eml = new map<Id,string>();
map<Id,Id>acct2con = new map<Id,Id>();

for(contact con:trigger.new)

   if(con.email != trigger.oldmap.get(con.Id).email){

      con2eml.put(con.Id, string.valueOf(con.email));

  list<Account>accts2up = new List<Account>();

  //One would be tempted to run the following query:

  // map<Id,Account>acctsMap = new map([SELECT Id, Account.Custom_Email__c FROM Account WHERE Id IN :con2up]);
  // however, it's not needed because we already have the account Id's


  for(Id ac:acctIds){
     account a = new account(Id=ac);
     //assign the new email
     a.Custom_Email__c = con2eml.get(acct2con.get(ac));       
     //add to list

   if(accts2up.isEmpty == false) update accts2up;
  • i am getting a following error at list<Account>accts2up = new List<Account>(); error is - Error: Compile Error: unexpected token: list at line 18 column 4 – Ankita Singh Jun 2 '15 at 8:49
  • it was a typo error..i removed the curly brace ..now it is giving me another error - Compile Error: Variable does not exist: string.valueOf.con.email at line 13 column 27 – Ankita Singh Jun 2 '15 at 9:03
  • i changed it to con2eml.put(con.id,con.email); but now its giving me another error at con2up.add(con.Id); Errror is - Compile Error: Incompatible element type Id for collection of Contact at line 12 column 7 – Ankita Singh Jun 2 '15 at 9:42
  • 1
    The bracket cannot be removed. I've restored the bracket. Without it, the for loop on acctIds runs once for each time through the for loop. I neglected to put parens around con.email in this line: con2eml.put(con.Id, string.valueOf(con.email)) which should fix any problems with the code. email is not a string, that is what the message is telling you. Without the parens, it wasn't converting it to a string properly. Were you not satisfied with @KeithC answer since you marked it as the solution? – crmprogdev Jun 2 '15 at 13:52
  • I am satisfied with the @keithc answer...i had to create a custom field on account onject and then bind it on VF page – Ankita Singh Jun 3 '15 at 9:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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