You need to sign in to do that
Don't have an account?
Issues with Trigger querying unrelated tables by Email
I'm writing a trigger to keep a persistent record of every Contact that has every opted out in a custom object called Opt Out Records. That way, even when they are deleted, and then imported again, they'll be marked "Opted Out" if they are in the Opt Out Records table. And any Contact that is marked Opted Out will have their email address written into the Opt Out Records table. We're keeping track of Opt Opts with a custom field called Communication Status.
So, what I have below works to an extent. It takes a batch of Contact records, picks up the entire Opt Out Records table (Issue #1), then rolls through looking for matches (Issue #2, related to #1). If a match is found, that Contact's Communication Status value is updated to "Opted Out". If a match isn't found, and the Contact is Opted Out, they are written into the Out Out Records table (stored and batch inserted, technically).
Issue #1: Pulling the entire Opt Out Records table doesn't make sense long term.
Issue#2: Neither does iterating in such a slow way through the Opt Out Records list for each incoming Contact. Eats up the governor very quickly.
So, my question, how do I more effectively identify which of the incoming Contacts' email addresses are already recorded in the Opt Out Records? I think that will solve both issues.
Thanks all.
trigger manageContactOptOut on Contact (before update, before insert) { List<Contact> theContacts = new List<Contact>(); for(Contact c : Trigger.new){ theContacts.add(c); theEmails.add(c.Email); } List<Opt_Out_Record__c> optOutList = new List<Opt_Out_Record__c>([SELECT Email__c from Opt_Out_Record__c]); Boolean foundOne = false; List<Opt_Out_Record__c> newOptOuts = new List<Opt_Out_Record__c>(); for(Contact myContact : Trigger.new){ for(Integer i=0; i < optOutList.size(); i++){ //We found their email address in the Opt Out Record object if(myContact.Email == optOutList[i].Email__c){ myContact.Communication_Status__c = 'No - Opted-Out'; foundOne = true; } } //We did NOT find their email address in the Opt Out Record object //If the Communication Status = Opted Out, then add it to the tracking object if (foundOne == false && myContact.Communication_Status__c == 'No - Opted-Out') { Opt_Out_Record__c newOptOut = new Opt_Out_Record__c(); newOptOut.Email__c = myContact.Email; newOptOuts.add(newOptOut); } foundOne = false; } try{ insert newOptOuts; }catch (Exception ex) { //Oops } }
Thanks, your query set me on the right track. Got it working now. If anyone sees any potential pitfalls in what I have, I'd love to hear them. One I just saw is the single item delete statement, I should batch that.
Pretty handy utility, now my Sales team can delete any Contacts or Leads they see fit, and if any of the Opted Out ones are imported again in the future, they'll automatically be marked Opted Out. If someone Opts In, they're simply removed from the Opt Out table.
Any other enhancements I should build into that?
All Answers
If theEmails is a Set, you could do you SOQL query this way:
then your double for-loop:
But is it possible to make contacts Inactive rather than deleting them? Then you could avoid some of these problems.
Thanks, your query set me on the right track. Got it working now. If anyone sees any potential pitfalls in what I have, I'd love to hear them. One I just saw is the single item delete statement, I should batch that.
Pretty handy utility, now my Sales team can delete any Contacts or Leads they see fit, and if any of the Opted Out ones are imported again in the future, they'll automatically be marked Opted Out. If someone Opts In, they're simply removed from the Opt Out table.
Any other enhancements I should build into that?