Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

I am looking to assemble an HTML Letterhead Email Template for an email service integration project.

There are two sObjects that hold this information - EmailTemplate and BrandTemplate.

BrandTemplate.value = broken HTML (styles aren't associated to tags) Letterhead with CDATA tags throughout to hold the email Template info

EmailTemplate.HTMLValue = User-created HTML email template

I've been trying to merge the two (don't need to worry about merge fields / codes) with little success.

I have tried turning both into XML, navigating the BrandTemplate.value field, but Salesforce does not natively support CDATA. I've also tried the polar opposite - stripping everything into text and doing replaces and substrings to assemble, but that also fails.

My end goal is to have a completed single HTML document consisting of both the BrandTemplate and EmailTemplate values.

Any hints / thoughts / clues?

share|improve this question
    
How exactly does it fail? –  jkraybill Jul 31 '12 at 23:47
    
There are two specific things that I'm running into issues with. One - if you look at the structure of the BrandTemplate.value field, there are CDATA sections in three main areas - header, body, and footer. Firstoff, I need to insert my EmailTemplate.HTMLValue into the body CDATA section. Two - all of the styling and image tags are not properly formatted in the BrandTemplate.value field, so I need to go in and deal with that too. If I had a full XML library that supported CDATA - not a prob, SF does not natively. –  Andy Boettcher Aug 1 '12 at 14:07
    
I've had some success in parsing / manipulating email templates using complicated regular expressions and String.replaceAll, does that offer a potential solution? –  jkraybill Aug 2 '12 at 0:31
    
There are two major things that i'm having issues with with the replaceAll method - the styles are in their own tags and I need to merge them with the immediately preceding tag, and the image tags have CDATA outside the tag with the actual src value, so I have to get them in the previous tag as well. All in all a major PITA. –  Andy Boettcher Aug 2 '12 at 4:00
    
I'd like to know how you managed to achieve this in the end. –  jmrjulian Jan 4 '13 at 4:35

3 Answers 3

Salesforce hacking time: I had this exact requirement, and was stuck for a while because of the weird connection between EmailTemplate and BrandTemplate, and the inability to leverage a merging/parsing function however, I found a solution, this is far from a clean solution, but it seems to be working perfectly.

First what you will do is, create a single email message (like you would send it from apex):

// Here we will build the single email message
Messaging.reserveSingleEmailCapacity(1);
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[]{'invalid@emailaddr.es'};
mail.setToAddresses(toAddresses);
mail.setUseSignature(false);
mail.setSaveAsActivity(false);
mail.setSenderDisplayName('MMPT');
mail.setTargetObjectId(UserInfo.getUserId());
mail.setTemplateId(sendTemplate.Id);

What we will do next is trick salesforce in sending the single email message, by setting a savepoint, sending the message and rolling back. The single email will not be send because of the rollback.

Savepoint sp = Database.setSavepoint();
Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});
Database.rollback(sp);

But now the beauty comes, because we triggered the sendEmail method, the email template got merged with the brandtemplate and the parsing took place. And you can find the parsed versions of your template components in the next variables (Subject, Text and HTML)

String mailTextBody = mail.getPlainTextBody();
String mailHtmlBody = mail.getHTMLBody();
String mailSubject = mail.getSubject();

This is far from what salesforce meant to do with single email message, and since we cannot leverage the platform parsing and merging functions, this did gave me a solution to this problem unfortunately through some hacking.

share|improve this answer
    
Thank you for this! You rock! –  Fernando F May 23 '13 at 20:48

When accessing templates and needing multiple objects I will
- select the template from the database
- define a merge syntax, use regular expressions "{!([A-z_]+)}" to get a key name - pass a map of data to replace the key (if exists) with data

you now have a template which is just a string. you can push the template to a VF page with or send an email manually in code.

code example:

public static Map<String,String> merge_template(Map<String,String> obj, EmailTemplate email){
    Map<String,String> data = new Map<String,String>();
    String html = email.HtmlValue;
    if(html!=null){
        html = m(html,obj,Pattern.compile('(\\{![A-Za-z_]+\\})').matcher(html));
        data.put('HtmlValue',html);
    }
    else{
        data.put('HtmlValue','');
    }
    String body = email.Body;
    String subject = email.Subject;
    body = m(body,obj,Pattern.compile('(\\{![A-Za-z_]+\\})').matcher(body));

    data.put('Body',body);

    return data;

}
private static String m(String body,Map<String,String> obj,Matcher m){
    while(m.find()){
      String merge_field = m.group(0);
      String field = merge_field.substring(1,merge_field.length()-1);
      String value;
      try{
        value = (String) obj.get(field);
      }
     catch(Exception e){
        value='';
     }
     if(value!=null){
        body = body.replace(merge_field,value);
     }
     else{
        body = body.replace(merge_field,'');
     }
    }
    return body;
}

public static Map<String,String> build(String template,Map<String,String> data){
    EmailTemplate[] tpls = [SELECT HtmlValue,Body,Subject FROM EmailTemplate WHERE DeveloperName = :template];
    if(tpls.isEmpty() == true){
        return "";
    }
    return merge_template(data,tpls.get(0);
}
share|improve this answer
1  
Do you have an example of this? –  Andy Boettcher Aug 8 '12 at 18:04
    
That's pretty cool ebt - let me pop around and let you know what I putter out. Thanks! –  Andy Boettcher Aug 17 '12 at 16:26
    
Hello, That looks great - it's exactly what I was looking for. Could you please explain to me what UtilsList.getFirst does? I get the error "Save Error: Variable does not exist:UtilsList". Thanks in advance. –  user8737 Jun 19 at 10:43
    
I used getFirst to cut down on the boilerplate conversion from a List to single object, but it turned out to be ill conceived. I updated the code to remove that reference. –  ebt Jun 19 at 16:43

You should be able to create a VF Email Template, and embed a VF Component within it to query those sObjects with an Apex controller.

share|improve this answer
    
That is correct, which I have done. However - the merging of those two values from the two sObjects is the problem. In your org, look at the values in those two fields and that's what I'm trying to merge together. Getting it to display in a Component isn't the question. =) –  Andy Boettcher Aug 1 '12 at 14:04

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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