I have a large list of email domains that I would like to use for comparisons within some apex code (for example, does the Contact's email domain name exist in this list).

What is the best practice for storing and updating these values? I've thought of adding them all to an Apex map, using Custom Settings, or storing as Custom Metadata Types but they all have trade-offs.

Wondering if there's a better way!


The options you specify there aren't mutually exclusive. There's two halves to this approach: (1), storing the domains you want to check for, and (2) performing the check for the domain name's presence in Apex.


Unless the list of domains is very small and unchanging, you won't want to hard-code it in Apex - you'd have to do a deploy every time you wanted to change it.

If you do not need inter-environment deployability, if you need to be able to delete records in code, or if you prefer a simple, synchronous Apex API for making updates and changes to the list, Custom Settings will be your preferred solution here.

If you need to deploy the domain list between different Salesforce environments via change set or Metadata API, Custom Metadata Types will be your preferred storage location. Note that the Apex API for manipulating records of CMTs does not support deletion and is asynchronous only.

I would store the domain names in a Unique External Id field on the Custom Settings object to maximize query performance. CMTs cannot have External Id fields, which may have implications for query performance depending on your data volume (I can't say I've benchmarked CMT queries against queries on an indexed field on Custom Settings).


Because you're working with a large number of records (I'm just going to assume we're talking hundreds or more), it's probably the limits-safest solution to iterate over the Contacts you want to evaluate to accumulate their email domains in a Set<String> and then issue a single query against your indexed External Id field. Then you build another Set<String> of only the matching domain names, so you can do constant-time membership checking:

Set<String> domainNames = new Set<String>();

// populate Contact domain name list
for (Contact c : myContactList) {

Set<String> matchedDomains = new Set<String>();
for (Domain_Setting__c d : [SELECT Domain_Name__c FROM Domain_Setting__c WHERE Domain_Name__c IN :domainNames]) {

// now, iterate over Contacts again

for (Contact c : myContactList) {
    String domain = getDomainNameForContact(c);
    if (matchedDomains.contains(domain.toLowerCase())) {
        // do something about it!

This is just a sketch (there's no error checking or null guards!), but I think a workable solution could be built around this structure.

| improve this answer | |
  • Thanks David, this is incredibly detailed and exactly what I was looking for! – McD Jul 26 '18 at 22:50

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.