When an Email Template Just Isn’t Enough

Sometimes your users need to send an email from within Salesforce. Most of the time the standard Send Email button will suffice. Other times however, your needs are more specific. For those times, developers often resort to using Visualforce email templates which can certainly meet just about any need. However, the drawback here is that the email content now lives in code. Being good developers, we don’t want our admins to have to worry about digging into code for things like this — unless they really want to — so we try to come up with a way to make the content of the email accessible. This was my exact requirement and here’s what I wound up doing. The code herein is very specific to the requirement in question but could be generalized a bit to make it more flexible or reusable (which is something I may just do at some point, but alas — deadlines. @Codefriar has already done some pretty cool stuff here.).

Here was my approach:

The Template:

I created a new Email Template just as one would for use in workflow email alerts etc. I then created a custom settings to store the ID of this email template in this particular application’s custom settings. I will use this ID later to get the ID of this template in my apex class.  In the content of this email I included the merge field syntax (more or less because it was familiar to people) for the fields that I knew I was going to be including later.  In the end I wound up with a template that looked something like this (any client identifiable content has been replaced with BLAH BLAH BLAH — I’m so creative…):

Dear {!Contact.Salutation} {!Contact.LastName},
I am pleased to attach the final BLAH BLAH BLAH document between {!Opportunity.Account} and the BLAH BLAH BLAH for your records.

BLAH BLAH BLAH is proud to work with {!businessTypePlural} such as yours to fulfill new opportunities in BLAH BLAH BLAH.

Thank you for your commitment to your employees, your community and the state of BLAH BLAH BLAH.

BLAH BLAH BLAH is always looking to improve our services. Please take the time to fill out a brief satisfaction survey using this link:

{!surveyLink}

Sincerely,
Some Person at BLAH BLAH BLAH

Some of those items I could have set using the standard setTargetObjectId, setWhatId methods available on Messaging.SingleEmailMessage, but those wouldn’t get me to some of the other data that I needed. So instead, I used the template merely for its body content and manually performed string replacements in my apex class on that body like so:

public EmailTemplate emailTemplate {
        get {
            if(emailTemplate == null) {
                Survey_Settings__c settings = Survey_Settings__c.getInstance();
                if(settings != null) {
                    emailTemplate = [SELECT Id
                                     , Subject
                                     , Body
                                     , HtmlValue 
                                     FROM EmailTemplate 
                                     WHERE ID = :settings.Contract_Email_Template_ID__c];     
                }
            }

            //send in the Contact for salutation purposes
            if(this.selectedContact != null) {
                Contact c = this.oppContacts.get(selectedContact);
                if(c != null) {
                    if(c.Salutation != null) {
                        emailTemplate.Body = emailTemplate.Body.replace('{!Contact.Salutation}', c.Salutation);    
                    } else if(c.FirstName != null) {
                        emailTemplate.Body = emailTemplate.Body.replace('{!Contact.Salutation}', c.FirstName);    
                    }
                    
                    emailTemplate.Body = emailTemplate.Body.replace('{!Contact.LastName}', c.LastName);
                }
            }

            emailTemplate.Body = emailTemplate.Body.replace('{!Opportunity.Account}', this.opp.Account.Name);
            emailTemplate.Body = emailTemplate.Body.replace('{!businessTypePlural}', this.opp.Account.Business_Type_Plural__c);
            
            return emailTemplate;    
        }
        set;
        
    }

Much of the above, (if not all) could have been achieved by just sending in my contact. I could have gotten most of the necessary information from there, however — in so doing, the body of the email would have been rendered but I still don’t have all of my information, particularly my survey link. I wouldn’t have my survey ID yet either as that doesn’t get created until my end user clicks send. By then it would be too late for me to stick the survey link since the email message would be already packaged up. (I did try this, before going this route but ran into some odd issues getting my link in the email message, so I backed out and moved forward with this plan). Add to that the fact that I wanted to show the content of the email WITH the substitutions in place to the end user for review.

Lastly, once the user has selected their attachment and has proofread, perhaps even modified the message (minus the link since it doesn’t exist  yet) they click send. I then save all the necessary objects, including my survey and stuff that into the email message before calling my sendEmail method.

private Messaging.SendEmailResult[] sendEmail() {
        Messaging.SingleEmailMessage msg = new Messaging.SingleEmailMessage();
        List attachments = new List();
        Messaging.EmailFileAttachment contractFile = new Messaging.EmailFileAttachment();
        contractFile.setFileName(emailFile.name);
        contractFile.setBody(emailFile.body);
        attachments.add(contractFile);
        msg.setFileAttachments(attachments);
        msg.setSubject(emailTemplate.Subject);
        msg.setToAddresses(new String[] { this.oppContacts.get(selectedContact).Email});
        msg.setHtmlBody(emailTemplate.Body);
        Messaging.SendEmailResult[] result = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {msg});
        return result;
    }

Which gets called from this hunk of code in my save method on the controller.

Survey_Settings__c settings = Survey_Settings__c.getInstance();
                if(settings != null && settings.Customer_Satisfaction_Survey_URL__c != null) {
                    String surveyUrl = settings.Customer_Satisfaction_Survey_URL__c + '?aid=' + this.survey.ID;
                    emailTemplate.Body = emailTemplate.Body.replace('{!surveyLink}', surveyUrl);    
                }   

                //send the email
                emailTemplate.Body = emailTemplate.Body.replace('\n', '
');
                Messaging.SendEmailResult[] result = sendEmail();

I then manually create an activity that logs this message and includes the body of the email in the description field of the task. The task is set to Completed in code so it goes directly to Activity History.

In the end, the solution provides full access to content to the admin, and full control over the flow complete with some extra automation that they couldn’t get out of their old process.

Hope this helps should ever find yourself in a similar situation…

 

:wq!

Getting Back to Basics

Sometimes we get so good at what we do or we do what we do so often, we wind up flying on auto-pilot. Whether this is evident in your personal life, or work life — its pretty much unavoidable. Given the nature of this blog however, I’m focusing on work life. Being a consultant, I get to poke around at numerous orgs. Most of these orgs have been around for longer than I have and may have perhaps lost their admin, never had an admin, or have just been “brought along for the ride” and when I show up there are many basic things I see that could possibly help the organization in question maintain a better environment for their data, especially when inviting “outsiders” into their org for support.

Here are some items for those entities that don’t have a dedicated salesforce admin to keep in mind when working in their org that go a very long way to producing an environment that is easily support or passed on from one admin to the next, etc.

  1. Fill out description fields, for everything. When adding a new field to a standard or custom object (or even just adding a new object, etc), you are given the option to fill out a description field. Use this. As far as what to say — think about what you would want to know about this field if you had no prior knowledge of your org.  Be explicit, and avoid company specific abbreviations etc. (As an outsider looking in for the first time, you’re likely not going to know all the internal vernacular used within a company, e.g TPS Reports). This has the added advantage of reminding yourself what a certain field is there and what it does should you not need to work with part of your org for sometime. If you’re at all like me, if its been off your plate for more than a week or so — you’ve forgotten it. The description field is a great reminder.
  2. Naming standards for fields: If you can, be explicit in your naming of fields.  A field name ip_Total__c might not be as clear as Internal_Product_Total__c. For a little more typing, you’re building documentation directly into your objects. Yes you can be more explicit in your labels, but speaking purely from a developer point of view, if I’m using Internal_Product_Total__c in my code instead of ip_Total__c, my code just got easier to read as well. (So thanks in advance for that!)
  3. Naming standards for everything: Okay so this may be a cheat just to add another number to this list, but lets forget that for a moment. Why not be as explicit as you can with the naming of things like workflow rules, workflow actions, email templates, email alerts. If it can be read/referenced why not make it clean and obvious what its doing or what its being used for? “Send Email” is nowhere near as clear as “Send Internal Products Total Goal Reached”, etc
  4. Eliminate cruft: This one is a bit tricky as I’m never a fan of deleting…anything, but I’ve poked around enough orgs that I’ve seen many an attempt at writing a validation or workflow rule only to abandon it later for one reason or another. If its in your org and never been used, or something you were just experimenting with — get rid of it. That’s what sandboxes and dev orgs are for. Which is a great segue…
  5. Don’t make changes in production: this is dangerous. Even if it seems harmless you can do bad things. Bad things, in case you were confused, are not good things (unless you learn from them, but again…you can learn from a sandbox or dev org as well). Playing the “what if” game in production is scary for your data…your data doesn’t like “what if” — it likes routine…and tidiness, and maybe long walks on the beach…data is king, honor your king…its good to be king.

To most of you reading this this is hopefully review, however since I only make the effort half the time myself, this is as much for me as it is the newbie who might be wandering out in the big world of Salesforce for the first time. (Do as I say, not as I do right?).

P.S. I promise I am working on some more technical “stuff” but I’m still fighting my way through some of what it is I want to show, but its coming…I swear…I have here somewhere…kinda.

 

:wq!

Handling Objections

Often times developers get set in their ways. We like our “norm” and don’t like to change things up all that often. Don’t get me wrong, many of us — perhaps most of us spend time with the “framework of the month” but usually wind up falling back into our platform of choice. I remember when I was fed up with all the various frameworks within the Java world and someone showed me CodeIgniter for PHP. I jumped ship as soon as I could and for the longest time nobody could sell me on anything else. I’d tried rails, and grails, and while those were “fun and new” I was just not as productive or enamored with what they supplied me. From there, someone showed me Django and though it took quite a while for me to gain an appreciation for it, I eventually crossed over. The frameworks were all similar enough in concept to keep me learning at a good pace and eventually it became my framework of choice.

Recently I was a “fly on the wall” during a conversation regarding the introduction of the Salesforce platform to a team of largely Java/Grails developers & while the voice in the room was playing devil’s advocate, he was simply spot on regarding some of the objections that his developers were going to throw at him. As I sat and listened intently (as I’ve been down that road before) I started to think of how I may respond to some of the objections.

  1. I don’t want to be locked into a frameworks way of doing things: lets be honest, there is not a single person on the planet that is part of a Java project that isn’t currently submitting to some framework’s way of doing things. You’re likely using Spring, JSF, Hibernate, etc. You’re doing things the frameworks way already, you’re actual objection is:  “This is new and I’m not used to/don’t want to learn something new.” The beauty here is that if you’re comparing it to Java — the languages are extremely similar and the front end templating is definitely nothing new if your used to jsp tags, JSF, etc. There is no lock-in here that you aren’t already experiencing. When you use a framework you’re accepting its way of doing things. This is no different than what you’re already doing, its just a different “lock.”
  2. Licensing costs — we currently have none: While this is true if you’re not in the .Net world, you likely don’t have licensing costs but you have server upkeep costs. Whether you colocate, outsource entirely, or have your own server room, there is quite a bit of cost built into maintaining your installations, configuring your app servers, locking down the security, applying patches, etc. And lets not forget how much “fun” it is troubleshooting JBoss stacktraces, load balancing your database servers etc. If you’re a server guy, great — you lasted a heck of alot longer than I did, but if you’re DevOps (by force) wouldn’t it be nice to focus less on the Ops and more on the Dev?  While I’ve not run any numbers, I’d bet that once you figure in maintenance of your servers, the licensing isn’t as bad as you’d think. (Lets talk High Availablity, redundancy, failover, disaster recovery another time…*ouch*)
  3. I like to build my front ends from the ground up: So do many people, and many still do. I still haven’t fully submitted myself to Visualforce and often times layout pages with standard HTML. I use JS libraries, stylesheets, the same tools that straight up HTML5 guys are using. The Salesforce platform allows all of this — and guess what? I’ve still managed to learn a thing or two outside of the platform.
  4. We already have a system in place that works for us: That’s great news, but should that force your company into doing things the same way even if given evidence of perhaps a better way of doing things? Shouldn’t you at least want your company to attempt to improve? It may very well be that your way is better, but a company that doesn’t at least explore other avenues in a quest for improvement is doing itself — and its employees — a huge disservice.

In the end we developers are a finicky bunch. We like what we like and many times we can’t really tell you why, or when we do — our arguments seem purely emotional and not always logical. As a developer, I’m trying to keep an open mind about things, and I’d like to think I’m fairly good at that most of the time. After all, I left Django and decided to learn the Salesforce platform. Yea, sure there are things I really miss about Django, but if I went back to Django, I’d miss things from Salesforce. Its about learning, the experience in trying new things. If you’re argument is that you don’t want to be pigeonholed into another framework but then only offer up your “goto solution” — aren’t you already pigeonholed? #FoodForThought

 

:wq!