function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
michael_mcmahonmichael_mcmahon 

Trigger to Send Single Email to Custom Object Email Address

I have tried for two full days to figure this out, now I'm asking for help.  Anyone feel like helping a total beginner?

 

We have a custom object, Person__c that allows unregistered visitors to submit basic business info about themselves and/or other people via a VisualForce page on a Force.com Site.  We need to send an email to each new entrant in the database, and to differentiate between Self-Submitted and Not-Self-Submitted.

 

I assume I need a trigger after insert, in order to ensure the submission was successful before sending out the email.  

 

Self-submitters will be waiting for a confirmation email, so emails need to be sent individually rather than batched.  Ultimately, non-self-submitted and  batch uploads could be handled by mass email but for now I think single email is probably what I need.  I thought I might use an if/else statement to differentiate between self and non-self submissions within the same trigger.

 

// Send single mail to each new Person who created their own new record
// as opposed to the record having been created by someone else
trigger NewPersonSelf on Person__c (after insert)
{for (Person__c p : Trigger.new) {

// I stupidly used the Name field to store Email
//check to see if the new Person__c record contains an Email
if
(p.Name != ' ' ) {
final String template();
//p.me__c is boolean for "self"
//if true then the person self-registered so
//use the NewPersonSelf template
if
(p.me__c = true) {'NewPersonSelfVF';
else {
'NewPersonNotSelfVF';
}
Messaging.SingleEmailMessage mail = new
Messaging.SingleEmailMessage();
}

mail.setTemplateID([select id from EmailTemplate where
Name = :template].id);
mail.setSaveAsActivity = (true) ;
mail.setTargetObjectId ;
mail.setWhatId ;
mail.setToAddresses = p.Name;
Messaging.sendEmail (new Messaging.SingleEmailMessage[] {mail});

}
}
}

 

and the test class, my first ever, which I include solely to demonstrate that I did make an effort and got to a whopping 30% coverage:

 

@isTest
private class NewPersonSelfTest {
static testMethod void testNewPersonSelf() {
Person__c testPerson = new Person__c();
{
testPerson.Name = 'name@some.com';
}
insert testPerson;

Messaging.Singleemailmessage testEmail;
List<Messaging.Sendemailresult> testEmailResults;
test.startTest();

test.stopTest();
}
}

 

Sean TanSean Tan

Try this for the trigger, then we can move on to the test method.

 

I'm not what what you wanted for the target object id or the what id so you'll have to set that yourself:

 

// Send single mail to each new Person who created their own new record
// as opposed to the record having been created by someone else
trigger NewPersonSelf on Person__c (after insert)
{
	Map<String, EmailTemplate> emailTemplateMap = new Map<String, EmailTemplate>{};
	
	for (EmailTemplate item : [ select Id, Name FROM EmailTemplate where Name IN ('NewPersonSelfVF','NewPersonNotSelfVF') ])
	{
		emailTemplateMap.put(item.Name, item);
	}
	
	Messaging.SingleEmailMessage[] emailMessageList = new Messaging.SingleEmailMessage[]{};
	for (Person__c p : Trigger.new) {
		
		// I stupidly used the Name field to store Email
		//check to see if the new Person__c record contains an Email
		if (p.Name.trim() != '' ) {			
			Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
			//p.me__c is boolean for "self"
			//if true then the person self-registered so
			//use the NewPersonSelf template
			if (p.me__c == true) 
			{
				mail.setTemplateID(emailTemplateMap.get('NewPersonSelfVF'));
			}
			else 
			{
				mail.setTemplateID(emailTemplateMap.get('NewPersonNotSelfVF'));
			}
						
			mail.setSaveAsActivity(true);
			//??? Not sure what ids you're trying to set here
			//put them in the brackets as per needed
			mail.setTargetObjectId();
			mail.setWhatId();
			mail.setToAddresses(new String[]{p.Name});
			emailMessageList.add(mail);			
		}
	}
	Messaging.sendEmail(emailMessageList);
}

 I've made the code bulk safe...

michael_mcmahonmichael_mcmahon

Thanks a million Sean.

 

I loaded your code and I'm getting this error.  I'm not sure if it's saying that it can't find the template, or that the new record wasn't added to the map.

11:51:55.107 (107158000)|FATAL_ERROR|System.QueryException: List has no rows for assignment to SObject

Trigger.NewPersonSelf: line 4, column 1
11:51:55.107 (107174000)|FATAL_ERROR|System.QueryException: List has no rows for assignment to SObject

Trigger.NewPersonSelf: line 4, column 1

mail.setTemplateID(emailTemplateMap.get('NewPersonSelfVF'));

Generates this error:
"Method does not exist or incorrect signature: [Messaging.SingleEmailMessage].setTemplateID(SOBJECT:EmailTemplate)"

 

I've triple-checked that these are VF templates, are loaded and available for use, and named correctly, and I attempted to create a new person twice with the same result.  I've used the Developer Console to construct SOQL queries that DO NOT yield any results for the email template, or for any email template though there are a few other VF templates in the Unfiled for Public Use folder that I'm assuming I'm supposed to use to make the templates available to the trigger.

 

Your help is appreciated.   Michael

 

 

Sean TanSean Tan

Most likely the user doesn't have access to query the templates, you can probably get around this by bypasing Salesforce security... try this:

 

// Send single mail to each new Person who created their own new record
// as opposed to the record having been created by someone else
trigger NewPersonSelf on Person__c (after insert)
{
    Map<String, EmailTemplate> emailTemplateMap = new TriggerUtil().getEmailTemplates();
    
    Messaging.SingleEmailMessage[] emailMessageList = new Messaging.SingleEmailMessage[]{};
    for (Person__c p : Trigger.new) {
        
        // I stupidly used the Name field to store Email
        //check to see if the new Person__c record contains an Email
        if (p.Name.trim() != '' ) {            
            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            
            EmailTemplate template;
            //p.me__c is boolean for "self"
            //if true then the person self-registered so
            //use the NewPersonSelf template
            if (p.me__c == true)
            {
                template = emailTemplateMap.get('NewPersonSelfVF');
            }
            else
            {
                template = emailTemplateMap.get('NewPersonNotSelfVF');
            }
            
            if (template != null)
            {
                mail.setTemplateId(template.Id);
            }
            mail.setSaveAsActivity(true);
            //??? Not sure what ids you're trying to set here
            //put them in the brackets as per needed
            mail.setTargetObjectId();
            mail.setWhatId();
            mail.setToAddresses(new String[]{p.Name});
            emailMessageList.add(mail);            
        }
    }
    
    if (!emailMessageList.isEmpty())
    {
        Messaging.sendEmail(emailMessageList);
    }
    
    private without sharing class TriggerUtil
    {
        public TriggerUtil()
        {
        }
        
        public Map<String, EmailTemplate> getEmailTemplates()
        {
            Map<String, EmailTemplate> tempMap = new Map<String, EmailTemplate>{};
            
            for (EmailTemplate item : [ select Id, Name FROM EmailTemplate where Name IN ('NewPersonSelfVF','NewPersonNotSelfVF') ])
            {
                emailTemplateMap.put(item.Name, item);
            }
            
            return tempMap;
        }
    }    
}

 

michael_mcmahonmichael_mcmahon

 

13:10:55:211 FATAL_ERROR System.NullPointerException: Attempt to de-reference a null object

This is in my sandbox, I'm the admin and have all priveleges.  I just tried also moving the templates from Unfiled Public to My Personal Email Templates but that didn't make any difference.

 

Other than to make the template Available for Use (which I've confirmed) I cannot find any other permission levels or profile level access or restrictions to EmailTemplate access. I've been working on this for 30+ hours over three days and I'm not giving up!  If there's a reference I haven't found to a more advanced email template management system I'm happy to learn how to use it, but I've read all the developer force docs I can find on outbound email and there don't seem to be many settings for email templates.

 

I'm also happy to fall back to text and html emails without the if statement if that would wrap things up, at least for now.

 

Thanks again for your time.

 

Michael

 

 

Sean TanSean Tan

Can you put the full stack trace and line number of where it's failing (and you're latest code)?

 

Also, can you check if the Email Template query is returning anything? If it is, can you check the case sensitivity of the names?

 

If not can you try moving them to a new email template folder that is public? (Instead of using the default folders).

michael_mcmahonmichael_mcmahon

YES!

 

It's working!  I hard-coded the email template IDs and worked through a couple other problems and now IT WORKS!

 

THANK YOU!!

 

 

I've got to take a break now, but I'll work on the test tonight.  Sean, I can't thank you enough man!   

Sean TanSean Tan

Be careful, I definitely don't recommend hard-coding Id's since it will become a problem when deploying to different orgs. Ideally you'll want to find out why you can't retrieve those email template records... maybe using the Force.com explorer can help to find out what's going on.

ForcepowerForcepower

I think checking for DeveloperName instead of Name may do the trick. Those template names looked like the developer names rather than the user friendly Name.