People often ask me about Web To Case -- how it's used, what it can do, and its limitations. I thought I'd take a moment today to discuss it.
First, let's start with the basics.
What is Web To Case and how does it work?
Web To Case is a means by which you can post a simple, unauthenticated web page that allows your customers to submit cases directly to your Salesforce.com instance. This means that you can post a public case submission page on your own website with your own branding and styling. In a nutshell, Web To Case works by generating for you a snippet of HTML. This HTML is a good old-fashioned HTML form that you can put on any page. When your customer presses Submit, the information on this form is posted directly to a Salesforce.com server, which handles the information, converts it to a case, and redirects the customer's browser back to a page of your choosing.
Setting up Web To Case requires a couple of steps; rather than regurgitating them all here, I will refer to the excellent documentation on the subject.
When your customer posts a case via Web To Case, a few fields are generally required, namely the name and the email address. These values will be stored in the newly created Case in the Web Name and Web Email fields. If that email address happens to be associated with a Contact in your system, then Web To Case will automatically associate that case with the contact who has that email address, and with the account associated to that contact. If that email address is not found, or Web To Case discovers more than one contact with that email address, then Web To Case will not know which contact to associate to the case. In that instance, it will leave the Contact and Account fields on the case blank and allow you to fill them (which you can generally find using those Web Name and Web Email fields).
What is Web To Case useful for?
Let's say that you're doing a lot of support by email. Emails are an unstructured medium, so even if you're automating the process with Email To Case , someone generally still has to look at the cases to classify them -- it's not easy to perform workflow on plain text. Web To Case allows your customers to submit the information directly into the individual fields on your case, so you can perform a great deal of automation, like workflow, assignment, and auto-response rules, immediately. That can save you a lot of man hours.
Meanwhile, Web To Case is a very quick way to put up a web form to accept cases. You can generally have a quick-and-dirty page up in minutes, and because it's standard HTML, it's easy to embed into an existing page.
What are Web To Case's limitations?
First, Web To Case is limited to receiving 500 cases per day. This is to keep things like spambots from beating up your org (and beating up Salesforce.com's servers). Speaking of spam, Web To Case does not perform any spam filtering. You could use workflow to filter out cases that appear to be spam, but Web To Case itself does not apply any particular intelligence -- it just takes the cases.
Web To Case cannot handle attachments.
This is a side effect of the simplicity of its setup, and of the simple transactional nature of HTTP. Taking attachments via the web is a remarkably complicated process. For instance, try attaching a document in Gmail. You'll notice that you first have to browse to a file; it posts that file immediately to the server. In the background, it associates your in-progress email with the file it just posted, so that when you finally go to send the email, it knows which attachments go with which email. So there are two posts involved here, plus a fair bit of backend logic. Web To Case, on the other hand, is a simple form with a single post that you can embed anywhere. Attachments don't play nice with that.
Out of the box, if Web To Case does not find a contact to associate a case to, it will not autocreate one. However, a previous blog post discusses how, with a simple Apex trigger, you can set your org up to do so.
Finally, Web To Case is solely a tool for the initial submission of cases. If your customers need to be able to track their cases, or add information to them after the initial submission, then you'll want to look into the Self Service Portal or the Customer Portal -- those are authenticated products that allow your customers to file cases, but also to follow up on them, browse the knowledge base, and in the case of the Customer Portal, lots of other things as well.
How can I work around the volume and attachment limitations?
If you need to take more than 500 cases per day, or you want to be able to take attachments, you can now do so using Salesforce.com's facility for unauthenticated access called Force.com Sites. There's a quick start you can follow on how to create a custom Web To Case form using Sites.
A blog reviving some of my most popular posts ever from the Salesforce.com blog world, and some brand new stuff too! Tips, tricks and sample code for Salesforce.com.
Monday, September 2, 2013
Monday, August 26, 2013
Service Cloud Basics: Auto-Response Rules
Every now and then I like to use this blog to take our readers back to basics and visit parts of the Salesforce.com application that they may have overlooked. Today's topic is none other than good old Auto-Response Rules.
Auto-Response Rules are a type of workflow that are available on Case and Lead. Broadly speaking, their function is to generate an email automatically in response to an incoming contact from a customer. They are often used in conjunction with Web To Case, Email To Case, and Web To Lead.
The great thing about auto-response rules is that they can automate that first response to the customer and provide that customer with a branded, professional-looking email that makes that customer feel that he has been heard. There can sometimes be a bit of confusion around when to use auto-response rules and when to use workflow email alerts. It can be fairly said that you can accomplish some of the same things with both. Auto-response rules have workflow-esque criteria, and like an email alert, they generate an email based on an email template. In some ways, workflow email alerts are more powerful in that they allow you to choose who to send the email to from a list of people who are related to the object, whereas auto-response rules only email the Contact on the case or the email address of the Lead.
Indeed, they are much alike, but auto-response rules are specially tailored for the use case of the first response to a customer contact, and they do have two very powerful features to that end. First of all, auto-response rules are processed sequentially, whereas workflow rules are processed in parallel. What does this mean?
Let's say I have two levels of support, Premier and Basic, and two products, Product A and Product B. If a Premier Support customer creates a case, I want to email him back with my Premier Support template, from my Premier Support email address. If the customer is Basic support, however, I want to send him an email from Basic Support using a template that differs by product.
If I were to try to model this using standard workflow rules, I would end up with at least 3 different rules, and with a convoluted set of criteria to ensure that I don't end up sending the email multiple times. Auto-response emails are different, though -- because they're processed sequentially, they are guaranteed to send at most one email. An auto-response rule will try each rule entry in sequence until it hits some criteria that matches, and it will send the email from that rule entry and stop processing the remainder of the rules. Here's how my auto-response rule might look in this example:
While it can seem at times that workflow email alerts and auto-response rules are identical, use cases like this one illustrate the differences. Happy emailing!
Auto-Response Rules are a type of workflow that are available on Case and Lead. Broadly speaking, their function is to generate an email automatically in response to an incoming contact from a customer. They are often used in conjunction with Web To Case, Email To Case, and Web To Lead.
The great thing about auto-response rules is that they can automate that first response to the customer and provide that customer with a branded, professional-looking email that makes that customer feel that he has been heard. There can sometimes be a bit of confusion around when to use auto-response rules and when to use workflow email alerts. It can be fairly said that you can accomplish some of the same things with both. Auto-response rules have workflow-esque criteria, and like an email alert, they generate an email based on an email template. In some ways, workflow email alerts are more powerful in that they allow you to choose who to send the email to from a list of people who are related to the object, whereas auto-response rules only email the Contact on the case or the email address of the Lead.
Indeed, they are much alike, but auto-response rules are specially tailored for the use case of the first response to a customer contact, and they do have two very powerful features to that end. First of all, auto-response rules are processed sequentially, whereas workflow rules are processed in parallel. What does this mean?
Let's say I have two levels of support, Premier and Basic, and two products, Product A and Product B. If a Premier Support customer creates a case, I want to email him back with my Premier Support template, from my Premier Support email address. If the customer is Basic support, however, I want to send him an email from Basic Support using a template that differs by product.
If I were to try to model this using standard workflow rules, I would end up with at least 3 different rules, and with a convoluted set of criteria to ensure that I don't end up sending the email multiple times. Auto-response emails are different, though -- because they're processed sequentially, they are guaranteed to send at most one email. An auto-response rule will try each rule entry in sequence until it hits some criteria that matches, and it will send the email from that rule entry and stop processing the remainder of the rules. Here's how my auto-response rule might look in this example:
While it can seem at times that workflow email alerts and auto-response rules are identical, use cases like this one illustrate the differences. Happy emailing!
Monday, August 19, 2013
The Contention-Proof Case Accept Button
The case accept button is a handy thing. It shows up on queue views to allow members of that queue to mass-accept cases (actually, in the Agent Console it shows up in the Mass Action dropdown rather than as a button, but it works the same). If you have a large queue, though, with lots of agents accepting cases at the same time, they may sometimes step on each others' toes. If two agents accept the same cases at almost the same time, then the last one will win, and the first agent will not actually own the cases he thinks he just accepted.
Here's some custom button code I wrote which addresses this issue. It only accepts cases that are still assigned to a queue; if the cases have been accepted by a user already, those cases will remain owned by the users who accepted them.
To add this code, go to Setup->Cases->Buttons and Links and make a new custom button called Accept Cases (or whatever label you'd like to use for this). Its Display Type should be set to List Button, its Behavior to Execute JavaScript, and its Content Source to OnClick JavaScript. Paste the code from this link into the OnClick JavaScript field.
Now you'll have to add this button to the Case list view. To do this, go to Setup->Cases->Search Layouts. Click Edit next to the Cases List View entry, and add your new button from the Available Buttons section to the Selected Buttons section.
So how did I do this? Quite easily really. Perhaps the most important part is the line that invokes {!GETRECORDIDS($ObjectType.Case)}. This little-known merge field allows you to get a list of all the IDs that are selected in a list view or related list -- really handy when you're trying to make buttons that act upon a large number of records. Once I have the IDs of the selected records, I run them through the also little-known retrieve function to get more information about them. The key to that retrieve call is getting Owner.Type -- that will return a string for each case containing either "Queue" or "User" depending on what the type of each case's owner is. A good lesson here is that GETRECORDIDS plus retrieve makes for a quick and powerful combination.
Now I divide the cases into two piles: the "accept" pile for cases that are currently owned by a queue that we're going to allow this user to accept, and the "reject" pile of cases that have already been accepted by other users. If there are any cases in the "accept" pile I call update on it to update those cases, and then I give some feedback to the user of the changes that were made (and the changes that were rejected). And there we have it: The Contention-Proof Case Accept Button. Note that with just a couple of minor changes you can adapt this same code for use with leads and custom objects -- any object that is ownable by a queue.
Here's some custom button code I wrote which addresses this issue. It only accepts cases that are still assigned to a queue; if the cases have been accepted by a user already, those cases will remain owned by the users who accepted them.
To add this code, go to Setup->Cases->Buttons and Links and make a new custom button called Accept Cases (or whatever label you'd like to use for this). Its Display Type should be set to List Button, its Behavior to Execute JavaScript, and its Content Source to OnClick JavaScript. Paste the code from this link into the OnClick JavaScript field.
Now you'll have to add this button to the Case list view. To do this, go to Setup->Cases->Search Layouts. Click Edit next to the Cases List View entry, and add your new button from the Available Buttons section to the Selected Buttons section.
So how did I do this? Quite easily really. Perhaps the most important part is the line that invokes {!GETRECORDIDS($ObjectType.Case)}. This little-known merge field allows you to get a list of all the IDs that are selected in a list view or related list -- really handy when you're trying to make buttons that act upon a large number of records. Once I have the IDs of the selected records, I run them through the also little-known retrieve function to get more information about them. The key to that retrieve call is getting Owner.Type -- that will return a string for each case containing either "Queue" or "User" depending on what the type of each case's owner is. A good lesson here is that GETRECORDIDS plus retrieve makes for a quick and powerful combination.
Now I divide the cases into two piles: the "accept" pile for cases that are currently owned by a queue that we're going to allow this user to accept, and the "reject" pile of cases that have already been accepted by other users. If there are any cases in the "accept" pile I call update on it to update those cases, and then I give some feedback to the user of the changes that were made (and the changes that were rejected). And there we have it: The Contention-Proof Case Accept Button. Note that with just a couple of minor changes you can adapt this same code for use with leads and custom objects -- any object that is ownable by a queue.
Monday, August 12, 2013
How To Turn Off The Interaction Log In The Service Cloud Console
Today I needed to turn off the Interaction Log in the Service Cloud Console. It was remarkably hard to figure out how to do so! As such I thought I'd document it here.
Interaction Logs are enabled on a per-page layout basis. As such, you'll need to edit each page layout to turn them off. To do so, edit the page layout of a primary tab object (in my example I'm using Contact). You'll find a button called Layout Properties at the top.
Click that button and you'll find a place where you can turn off the Interaction Log.
Press OK. Don't forget to press Save on the page layout!
Now go back to the Console. If you already had a contact open (or whatever object you were editing the page layout of), you may find that it still has the Interaction Log on it. Don't be alarmed -- just close that tab and reopen it. Any new object of that type will be rendered without the Interaction Log.
Bonus for advanced users:
If you've got lots and lots of page layouts and you don't want to go through all of them turning off the Interaction Log for every one, use the Force.com IDE instead. Set it to download all the relevant page layouts. Then do a find-and-replace across all files for:
<showInteractionLogPanel>true</showInteractionLogPanel>
And change it to:
<showInteractionLogPanel>false</showInteractionLogPanel>
Now save them all, and voila, the Interaction Log is off in all your layouts.
Interaction Logs are enabled on a per-page layout basis. As such, you'll need to edit each page layout to turn them off. To do so, edit the page layout of a primary tab object (in my example I'm using Contact). You'll find a button called Layout Properties at the top.
Click that button and you'll find a place where you can turn off the Interaction Log.
Press OK. Don't forget to press Save on the page layout!
Now go back to the Console. If you already had a contact open (or whatever object you were editing the page layout of), you may find that it still has the Interaction Log on it. Don't be alarmed -- just close that tab and reopen it. Any new object of that type will be rendered without the Interaction Log.
Bonus for advanced users:
If you've got lots and lots of page layouts and you don't want to go through all of them turning off the Interaction Log for every one, use the Force.com IDE instead. Set it to download all the relevant page layouts. Then do a find-and-replace across all files for:
<showInteractionLogPanel>true</showInteractionLogPanel>
And change it to:
<showInteractionLogPanel>false</showInteractionLogPanel>
Now save them all, and voila, the Interaction Log is off in all your layouts.
Monday, August 5, 2013
Reporting On Percentage Of Cases By Origin
The original version of this blog post comes courtesy of guest blogger and all-around Salesforce.com guru Jay Thayer (I've since modified it to apply to the new Report Builder).
Let's say you're trying to build a common report, Cases By Origin, but with a twist -- you want to know what percent of your interactions are coming via each channel. Well, you could build a dashboard with it and eyeball it, but that's not very satisfying -- sometimes you just want cold, hard numbers. The good news is that there is in fact a way to do it using some little-known capabilities of custom summary fields.
First, start by making yourself a standard Cases By Origin report by creating a custom report. Search for the report type simply called Cases -- we don't need any related objects for this report. Next make it a Summary Report by choosing that as the Format:
Now drag the Case Origin field onto the "Drop a field here to select a grouping" header. This will group your cases by origin, so we're nearly there.
On the top of the left hand side you'll notice an Add Formula icon. Drag that right on top of your Case Origin grouping (in the blue area).
This type of field will allow us to do math using both a summary of the group items and a summary of the whole report -- that's exactly what we need to calculate our percentages. First, at the top of the page, give the formula field a name, and set its Format to Percent. Now set it to display at Grouping 1: Case Origin, because that's the granularity at which we want this calculation to occur.
Now let's go to the formula builder and build it up. In order to calculate the percentage for each group, we need the record count for that group, and then we have to divide that by the total number of records in the report. To get the record count for the group, we use the handy-dandy Summary Fields > dropdown, where you'll find that the top item is called Record Count. That inserts an item that says "RowCount." That was easy enough.
Now we have to divide that value by the record count of the entire report. For that, we can use one of the Custom Summary Functions -- to view them all, click the Functions dropdown. Here we see a function called PARENTGROUPVAL. This is exactly what we need, because in this case the parent group is the entire report. Our only grouping summary is Grand Summary, which is fine because that's what we want.
Double-clicking PARENTGROUPVAL adds the following to our report:
PARENTGROUPVAL(summary_field, GRAND_SUMMARY).
Now we just have to select the summary field. Select that "summary_field" part of the above, and replace it with RowCount, so it says:
PARENTGROUPVAL(RowCount, GRAND_SUMMARY)
So your final formula should read:
RowCount/PARENTGROUPVAL(RowCount, GRAND_SUMMARY)
That will divide the rows in the current group by the rows in the entire report. The completed formula field should look like this:
Save your custom summary formula field by pressing OK, and proceed with the report wizard as usual, selecting and ordering your columns and entering criteria. When you run the report, you'll see that it's grouped by Case Origin, and each group is tagged with the percentage of total cases that came from that origin: Eureka!
Let's say you're trying to build a common report, Cases By Origin, but with a twist -- you want to know what percent of your interactions are coming via each channel. Well, you could build a dashboard with it and eyeball it, but that's not very satisfying -- sometimes you just want cold, hard numbers. The good news is that there is in fact a way to do it using some little-known capabilities of custom summary fields.
First, start by making yourself a standard Cases By Origin report by creating a custom report. Search for the report type simply called Cases -- we don't need any related objects for this report. Next make it a Summary Report by choosing that as the Format:
Now drag the Case Origin field onto the "Drop a field here to select a grouping" header. This will group your cases by origin, so we're nearly there.
On the top of the left hand side you'll notice an Add Formula icon. Drag that right on top of your Case Origin grouping (in the blue area).
This type of field will allow us to do math using both a summary of the group items and a summary of the whole report -- that's exactly what we need to calculate our percentages. First, at the top of the page, give the formula field a name, and set its Format to Percent. Now set it to display at Grouping 1: Case Origin, because that's the granularity at which we want this calculation to occur.
Now let's go to the formula builder and build it up. In order to calculate the percentage for each group, we need the record count for that group, and then we have to divide that by the total number of records in the report. To get the record count for the group, we use the handy-dandy Summary Fields > dropdown, where you'll find that the top item is called Record Count. That inserts an item that says "RowCount." That was easy enough.
Now we have to divide that value by the record count of the entire report. For that, we can use one of the Custom Summary Functions -- to view them all, click the Functions dropdown. Here we see a function called PARENTGROUPVAL. This is exactly what we need, because in this case the parent group is the entire report. Our only grouping summary is Grand Summary, which is fine because that's what we want.
Double-clicking PARENTGROUPVAL adds the following to our report:
PARENTGROUPVAL(summary_field, GRAND_SUMMARY).
Now we just have to select the summary field. Select that "summary_field" part of the above, and replace it with RowCount, so it says:
PARENTGROUPVAL(RowCount, GRAND_SUMMARY)
So your final formula should read:
RowCount/PARENTGROUPVAL(RowCount, GRAND_SUMMARY)
That will divide the rows in the current group by the rows in the entire report. The completed formula field should look like this:
Save your custom summary formula field by pressing OK, and proceed with the report wizard as usual, selecting and ordering your columns and entering criteria. When you run the report, you'll see that it's grouped by Case Origin, and each group is tagged with the percentage of total cases that came from that origin: Eureka!
Monday, July 29, 2013
Allowing Customer Portal Users To Edit Their Own Contact Information
Customer Portal users have the ability to edit some information about themselves via the My Profile page. That page allows them to edit their own User record, but not their own Contact or Account record. However, the User record does have some fields in common with Contact and Account, and with a quick bit of Apex, you can make it such that when the portal user updates his information, that gets reflected in his Contact or Account record as well.
To allow portal users to see the My Profile link, go to Setup->Home->Home Page Layouts. Make a separate home page layout for your Customer Portal (if youhaven't already done so) and add the Customer Portal Welcome componentto the top of it. That will render a little area in the sidebar with a My Profile link (which will allow them to edit their user information) and a Logout link.
Now to synchronize that User information with the Contact information. The example given here shows that synchronization just with the Contact, but it can easily be modified to apply to an Account or a Person Account. While the code itself is simple, it's not as straightforward as it seems. As this page of the Apex docs indicates, you can't just make a User trigger that updates a Contact or an Account, because it's forbidden to modify those "non-setup" objects from a "setup" object like User. Fortunately there is a simple solution: the @future annotation . The @future annotation allows you to create Apex that runs asynchronously at some point in the future (in my tests I've found that it runs immediately, or at least very soon after the trigger executes). Methods that use @future are subject to different limits than normal trigger operations because @future methods don't hold up the trigger (and therefore the entire user experience) while they're working. Therefore @future methods are often used to perform long-running web service callouts from triggers asynchronously. However, they can also be handy for a case like ours, where we want to update an object that we're not normally eligible to update. Here I'll show some snippets of code that allow me to accomplish this synchronization.
You can download the full trigger and class including test methods at the Developing with Service Cloud page here.
Calling a method that has been marked as @future is just like calling any other static method. Here's my trigger, short and sweet:
trigger UpdateContactFromPortalUser on User (after update) {
//We only want to run on the single item that the user edited
if (Trigger.new.size()==1)
{
User u =_ Trigger.new[0];
//And only if it's a portal user
if (u.ContactId!=null) {
UpdateContactFromPortalUser.updateContacts(u.Id);
}
}
}
My @future method is named UpdateContactFromPortalUser.updateContacts. Let's see how that works.
In the example given here, I just update a couple of fields from the user record: the name, the email address, and the title.
global class UpdateContactFromPortalUser {
@future public static void updateContacts(String userId) {
User u = [select ContactId,Email,FirstName,LastName,Title
from User
where Id=:userId];
if (u!=null && u.ContactId!=null) {
Contact c = new Contact (Id=u.ContactId,Email=u.Email,FirstName=u.FirstName,LastName=u.LastName,Title=u.Title);
update c;
}
}
...
}
(note that the above is just a snippet -- download the whole class here)
By putting the @future above my method, I'm telling the system that when I call this method, it should be run asynchronously. This allows me to bypass those pesky trigger restrictions and update my contact. Note that the @future method does impose some constraints: the method has to be static, return void, and cannot take sObjects as parameters (which is why I passed the user ID in instead of the User sObject itself).
That's all there is to it!
To allow portal users to see the My Profile link, go to Setup->Home->Home Page Layouts. Make a separate home page layout for your Customer Portal (if youhaven't already done so) and add the Customer Portal Welcome componentto the top of it. That will render a little area in the sidebar with a My Profile link (which will allow them to edit their user information) and a Logout link.
Now to synchronize that User information with the Contact information. The example given here shows that synchronization just with the Contact, but it can easily be modified to apply to an Account or a Person Account. While the code itself is simple, it's not as straightforward as it seems. As this page of the Apex docs indicates, you can't just make a User trigger that updates a Contact or an Account, because it's forbidden to modify those "non-setup" objects from a "setup" object like User. Fortunately there is a simple solution: the @future annotation . The @future annotation allows you to create Apex that runs asynchronously at some point in the future (in my tests I've found that it runs immediately, or at least very soon after the trigger executes). Methods that use @future are subject to different limits than normal trigger operations because @future methods don't hold up the trigger (and therefore the entire user experience) while they're working. Therefore @future methods are often used to perform long-running web service callouts from triggers asynchronously. However, they can also be handy for a case like ours, where we want to update an object that we're not normally eligible to update. Here I'll show some snippets of code that allow me to accomplish this synchronization.
You can download the full trigger and class including test methods at the Developing with Service Cloud page here.
Calling a method that has been marked as @future is just like calling any other static method. Here's my trigger, short and sweet:
trigger UpdateContactFromPortalUser on User (after update) {
//We only want to run on the single item that the user edited
if (Trigger.new.size()==1)
{
User u =_ Trigger.new[0];
//And only if it's a portal user
if (u.ContactId!=null) {
UpdateContactFromPortalUser.updateContacts(u.Id);
}
}
}
My @future method is named UpdateContactFromPortalUser.updateContacts. Let's see how that works.
In the example given here, I just update a couple of fields from the user record: the name, the email address, and the title.
global class UpdateContactFromPortalUser {
@future public static void updateContacts(String userId) {
User u = [select ContactId,Email,FirstName,LastName,Title
from User
where Id=:userId];
if (u!=null && u.ContactId!=null) {
Contact c = new Contact (Id=u.ContactId,Email=u.Email,FirstName=u.FirstName,LastName=u.LastName,Title=u.Title);
update c;
}
}
...
}
(note that the above is just a snippet -- download the whole class here)
By putting the @future above my method, I'm telling the system that when I call this method, it should be run asynchronously. This allows me to bypass those pesky trigger restrictions and update my contact. Note that the @future method does impose some constraints: the method has to be static, return void, and cannot take sObjects as parameters (which is why I passed the user ID in instead of the User sObject itself).
That's all there is to it!
Monday, July 22, 2013
Another Way To Skip The Case Close Page
Some time ago I wrote about The Quick Case Close Button as one means of skipping the Close Case page. In fact, there's another way to close cases quickly: you can show closed case statuses directly in the Status field of Case. This is not enabled by default, so many people miss this option.
You'll find the options that enable this in Setup->Customize->Case->Support Settings, and there are two of them.
Show Closed Statuses in Case Status Field does exactly what its name implies: it allows you to show closed case statuses right in that Status field. This means you can actually create a case and close it in a single step. Once you have closed statuses in that Status field, you can hide the Close Case button on the Case detail page by editing the Case page layout.
However, the page layout editor does not allow you to control the buttons on the edit page, and so you may be left with one redundant button, namely the Save & Close button. Fortunately there's another option for that on the Support Settings page, namely the Hide Save & Close Button. When this is enabled, the Save & Close button disappears from the edit page also.
For many Salesforce.com customers, this little addition should reduce the number of clicks it takes for their agents to create and close a case.
You'll find the options that enable this in Setup->Customize->Case->Support Settings, and there are two of them.
Show Closed Statuses in Case Status Field does exactly what its name implies: it allows you to show closed case statuses right in that Status field. This means you can actually create a case and close it in a single step. Once you have closed statuses in that Status field, you can hide the Close Case button on the Case detail page by editing the Case page layout.
However, the page layout editor does not allow you to control the buttons on the edit page, and so you may be left with one redundant button, namely the Save & Close button. Fortunately there's another option for that on the Support Settings page, namely the Hide Save & Close Button. When this is enabled, the Save & Close button disappears from the edit page also.
For many Salesforce.com customers, this little addition should reduce the number of clicks it takes for their agents to create and close a case.
Monday, July 15, 2013
The Quick View Tab
Lots of people would love to have a tab that just opens directly to a view of their choice. Unfortunately, standard object tabs can only open the relevant standard overview page, which shows a list of recently viewed cases -- that page can't be preset to open a certain view as soon as you hit the tab. However, you can create a custom tab which will instantly redirect itself to the view you'd like. Here's how.
The most common request I get is to create a tab for views on Case, so that's the example I'll give here. Of course, this technique can be used to create a tab for any kind of view for any object.
First, navigate to the view you'd like to tab-ify by going to the overview page and selecting that view. In my case, I'll go to the Cases tab and click on the Open Cases view, which is a view I created that shows all the open cases in my org.
Save the URL of this view; you'll need it later. It will look something like
https://na1.salesforce.com/500?fcf=00B300000031l4H
Now go to Setup->Customize->Create->Tabs. Click the New button under Web Tabs. Set it to Full Page Width. Set the Tab Type to URL, and give it a label that makes sense (I called mine "Open Cases" but you can call yours "Cases" if you intend to hide the normal case tab -- just make sure you don't end up with 2 tabs labelled "Cases"). Pick any Tab Style -- it's going to redirect to the Case tab anyway so this doesn't matter.
On the next page of the wizard, enter the following in the Button or Link URL:
javascript:parent.navigateToUrl('<your url here>');
Don't forget those single-quotes around the URL. So in my example it looks like this:
javascript:parent.navigateToUrl('https://na1.salesforce.com/500?fcf=00B300000031l4H');
And voila! You now have a tab that navigates directly to your view.
Bear in mind that a quick JavaScript navigation of this sort breaks the Back button minorly -- if you click this tab and then hit the back button, you'll get bounced right back to your view. You have to click the Back button twice in rapid succession to get back where you started. Consider yourself warned!
The most common request I get is to create a tab for views on Case, so that's the example I'll give here. Of course, this technique can be used to create a tab for any kind of view for any object.
First, navigate to the view you'd like to tab-ify by going to the overview page and selecting that view. In my case, I'll go to the Cases tab and click on the Open Cases view, which is a view I created that shows all the open cases in my org.
Save the URL of this view; you'll need it later. It will look something like
https://na1.salesforce.com/500?fcf=00B300000031l4H
Now go to Setup->Customize->Create->Tabs. Click the New button under Web Tabs. Set it to Full Page Width. Set the Tab Type to URL, and give it a label that makes sense (I called mine "Open Cases" but you can call yours "Cases" if you intend to hide the normal case tab -- just make sure you don't end up with 2 tabs labelled "Cases"). Pick any Tab Style -- it's going to redirect to the Case tab anyway so this doesn't matter.
On the next page of the wizard, enter the following in the Button or Link URL:
javascript:parent.navigateToUrl('<your url here>');
Don't forget those single-quotes around the URL. So in my example it looks like this:
javascript:parent.navigateToUrl('https://na1.salesforce.com/500?fcf=00B300000031l4H');
And voila! You now have a tab that navigates directly to your view.
Bear in mind that a quick JavaScript navigation of this sort breaks the Back button minorly -- if you click this tab and then hit the back button, you'll get bounced right back to your view. You have to click the Back button twice in rapid succession to get back where you started. Consider yourself warned!
Monday, July 8, 2013
Stamping A "First Response" Field When An Email Goes Out On A Case
A common service-level agreement (or SLA) in the support world is the first response time. Support organizations are often contractually obligated to respond to a given case within a certain number of hours. It is a little-known fact that you can use Salesforce.com to manage this type of SLA using simple workflow rules -- no Apex Code required!
First, we should note the existence of the Entitlements Processes functionality built into Salesforce.com. This capability allows you to measure and track your response, workaround and resolve time SLAs, both in calendar hours and business hours, so if you have some significant entitlement and SLA needs, Entitlements Processes are worth checking out. It's fairly involved to set that up, though, so today's post is focused more on people with more lightweight needs. Today we'll look at just using a simple workflow rule to stamp your first response time.
Your first step will be to add a First Response date/time field to Case. Next, if you haven't turned on Email To Case, do so by going to Setup->Case->Email To Case. You don't even have to activate any routing addresses. The reason for this is that once you have turned on Email To Case, there's an object under case called Email Message.
You can make workflows on this Email Message object which update the parent Case. So your next step is to create a workflow rule on the Email Message object. Here, set your criteria such that you stamp your field when the email message is outbound (i.e. "Is Incoming equals false") and the First Response field is empty (because you don't want to stamp it again once it's been stamped).
Finally, put a field update on this workflow rule to stamp the First Response field to NOW().
That's all it takes -- once you activate this workflow rule, your First Response field will begin getting stamped immediately, and you can start reporting on it.
Also: Note that if you are using the Customer Portal or Self-Service Portal, another means of responding to your customers would be via a public Case Comment. You can use a very similar process to that given above to stamp your First Response field from a Case Comment -- just set the object on the workflow rule to Case Comment instead of Email Message.
First, we should note the existence of the Entitlements Processes functionality built into Salesforce.com. This capability allows you to measure and track your response, workaround and resolve time SLAs, both in calendar hours and business hours, so if you have some significant entitlement and SLA needs, Entitlements Processes are worth checking out. It's fairly involved to set that up, though, so today's post is focused more on people with more lightweight needs. Today we'll look at just using a simple workflow rule to stamp your first response time.
Your first step will be to add a First Response date/time field to Case. Next, if you haven't turned on Email To Case, do so by going to Setup->Case->Email To Case. You don't even have to activate any routing addresses. The reason for this is that once you have turned on Email To Case, there's an object under case called Email Message.
You can make workflows on this Email Message object which update the parent Case. So your next step is to create a workflow rule on the Email Message object. Here, set your criteria such that you stamp your field when the email message is outbound (i.e. "Is Incoming equals false") and the First Response field is empty (because you don't want to stamp it again once it's been stamped).
Finally, put a field update on this workflow rule to stamp the First Response field to NOW().
That's all it takes -- once you activate this workflow rule, your First Response field will begin getting stamped immediately, and you can start reporting on it.
Also: Note that if you are using the Customer Portal or Self-Service Portal, another means of responding to your customers would be via a public Case Comment. You can use a very similar process to that given above to stamp your First Response field from a Case Comment -- just set the object on the workflow rule to Case Comment instead of Email Message.
Monday, July 1, 2013
How To Create A Mass Email Distribution List in Salesforce.com
Today we have a quick but common question from the Salesforce.com Answers boards. People often ask, "I want to email a bunch of people from Salesforce.com at once. How do I do that?"
Note that this post covers how to send an email from Salesforce.com's default Campaign functionality. Just prior to when this blog was posted, Salesforce.com acquired ExactTarget, which is a much more industrial-strength solution for outbound email. This blog post is intended for people that just need to send mass emails to 1000 or less people.
The answer is a little bit roundabout, but:
1. Create a Campaign that will represent your mailing list. If you can't see the Campaigns tab, be sure that in your user record Marketing User is checked on, and that in your profile you have create access for Campaigns.
2. Either fill the campaign manually using the Edit Campaign Members button, or create a report on Contacts with the criteria as needed and press the Add To Campaign button to fill your campaign.
3. Now go to the Contacts tab and click Create New View. Set it to All Contacts, put no criteria on it, and enter your campaign in the Filter By Campaign box. Save the view.
4. Go back to the Contacts tab and click the link entitled Mass Email Contacts. Select the view you created in step 3, select your email template, and you're off to the races.
Note that a campaign can contain either Contacts or Leads (or both), so if you want to email Leads instead, modify steps 3 slightly to say "Go to the Leads tab" and "click the link entitled Mass Email Leads."
Note that this post covers how to send an email from Salesforce.com's default Campaign functionality. Just prior to when this blog was posted, Salesforce.com acquired ExactTarget, which is a much more industrial-strength solution for outbound email. This blog post is intended for people that just need to send mass emails to 1000 or less people.
The answer is a little bit roundabout, but:
1. Create a Campaign that will represent your mailing list. If you can't see the Campaigns tab, be sure that in your user record Marketing User is checked on, and that in your profile you have create access for Campaigns.
2. Either fill the campaign manually using the Edit Campaign Members button, or create a report on Contacts with the criteria as needed and press the Add To Campaign button to fill your campaign.
3. Now go to the Contacts tab and click Create New View. Set it to All Contacts, put no criteria on it, and enter your campaign in the Filter By Campaign box. Save the view.
4. Go back to the Contacts tab and click the link entitled Mass Email Contacts. Select the view you created in step 3, select your email template, and you're off to the races.
Note that a campaign can contain either Contacts or Leads (or both), so if you want to email Leads instead, modify steps 3 slightly to say "Go to the Leads tab" and "click the link entitled Mass Email Leads."
Monday, June 24, 2013
Reporting On "Cases Filed By My Accounts"
The other day a poster on the Best Practices board asked whether there was a way to filter a report on Cases by "My Accounts." By default, Case reports are filterable by the case owner, but not by account. Fortunately, there is a way to do this, it's just a little roundabout: you have to create a case report which is driven off of Account using Custom Report Types. Here's how.
- Go to Setup->App Setup->Create->Report Types.
- Make a new Custom Report Type. Select the primary object as Account.
- On the next screen set the "B" object to Cases -- I use "with or without cases" so you can see accounts of yours that have no cases onthem.
- Save it. Now go to the reports tab and make a report of this type. When you get to the filter part you'll see that you can now filter by "My Account." You can also add regular criteria to case fields like Case.IsClosed so that you only see the open cases in the report, for example.
Monday, June 17, 2013
Workflow From Case Comments
Workflow From Case Comments gives you the ability to create a workflow rule on the Case Comments object. From that rule, you can create a field update that takes effect on either the comment itself or on the parent case.
For example, let's say I have a process whereby I set my case to a status of "Awaiting Customer Response" when I'm waiting for the customer to get back to me. Now my customer logs into the Customer Portal and adds a comment to the case. That constitutes a response, so the system should automatically set my case back to a "Working" status.
All I have to do is write a workflow rule on Case Comment with the requisite criteria (and the criteria can refer to items from the Case as well). Once that's done, I can make a field update that updates the status field on the case.
As people begin creating workflows from Case Comments, they inevitably notice some restrictions about these workflow rules. They ask, what if I want to send an email to the case owner? Why can't the email alert find that field?
As with workflow from Email Messages, Workflow From Case Comments is a "chaining" workflow -- it can trigger other workflow rules. Certain operations on Case Comment are limited because of what the workflow action is "looking at" -- an Email Alert, for example, is "looking at" the Case Comment and so cannot see the Case Owner, for example. However, you can put an email alert on a workflow on the parent case, and that workflow will get triggered and send out the email (and the email will be associated to the parent case, as you might expect).
So, although you can't send an email directly from a Workflow From Case Comments, you can put an email alert on the parent case. So, for example, you might make a Workflow From Case Comments that updates a "Last Comment" field on the parent case with the text of the most recent comment, and then make a workflow on Case which emails out that last comment to the Case Owner, or to certain members of the Case Team.
For example, let's say I have a process whereby I set my case to a status of "Awaiting Customer Response" when I'm waiting for the customer to get back to me. Now my customer logs into the Customer Portal and adds a comment to the case. That constitutes a response, so the system should automatically set my case back to a "Working" status.
All I have to do is write a workflow rule on Case Comment with the requisite criteria (and the criteria can refer to items from the Case as well). Once that's done, I can make a field update that updates the status field on the case.
As people begin creating workflows from Case Comments, they inevitably notice some restrictions about these workflow rules. They ask, what if I want to send an email to the case owner? Why can't the email alert find that field?
As with workflow from Email Messages, Workflow From Case Comments is a "chaining" workflow -- it can trigger other workflow rules. Certain operations on Case Comment are limited because of what the workflow action is "looking at" -- an Email Alert, for example, is "looking at" the Case Comment and so cannot see the Case Owner, for example. However, you can put an email alert on a workflow on the parent case, and that workflow will get triggered and send out the email (and the email will be associated to the parent case, as you might expect).
So, although you can't send an email directly from a Workflow From Case Comments, you can put an email alert on the parent case. So, for example, you might make a Workflow From Case Comments that updates a "Last Comment" field on the parent case with the text of the most recent comment, and then make a workflow on Case which emails out that last comment to the Case Owner, or to certain members of the Case Team.
Monday, June 10, 2013
Using Visualforce Components Defined in a Managed Package
As part of our KXEN Predictive Offers package, we define a couple of Visualforce components. This has two purposes. First, it fosters code reuse: we reuse these components on pages within our package that apply to Contacts, Leads and PersonAccounts, so we don't have to duplicate a bunch of Visualforce code. Then, our customers may want to embed the capability to show an offer into a larger Visualforce page, so they can use these components themselves in their own pages.
In testing the latter capability today, I ran into a buzzsaw of incomplete and hard-to-find documentation on the Salesforce.com side, so I am going to address it here so that folks googling this topic in the future might find this.
The first issue was that, in attempting to use our component in a target org, it was not found. I was specifying it just as we do in our own pages, like this:
<c:ShowOfferConsole userId="{!Contact.Id}"/>
This was buzzsaw #1: within our package, we can refer to the component using the standard c: notation. The component was global, so I should be able to use it, right? I also tried c:Offers__ShowOfferConsole, thinking maybe the kind of namespacing you do in Apex would work, but no dice there. Finally I figured it out: outside our package I had to refer to it via its package namespace (which in this case is "Offers"), like this:
<Offers:ShowOfferConsole userId="{!Contact.Id}"/>
Great! That only took me about an hour to figure out! But it still didn't work, now for a different reason. Now I get this error:
Error: Cannot use attribute userid (in component offers:showofferconsole) without global access in a component/page that is not in the same namespace as the component in my_visualforce_page at line 117 column 61
This took a while to track down. The component is global, yes, so I should be able to use it; but in components, like in Apex classes, you also have to make the individual attributes global in order to access them from outside the package. Fortunately this is our own package so we can modify the code, and here we needed to modify the component to make the userId attribute global. Now, finally, I can use the component outside the package!
In testing the latter capability today, I ran into a buzzsaw of incomplete and hard-to-find documentation on the Salesforce.com side, so I am going to address it here so that folks googling this topic in the future might find this.
The first issue was that, in attempting to use our component in a target org, it was not found. I was specifying it just as we do in our own pages, like this:
<c:ShowOfferConsole userId="{!Contact.Id}"/>
This was buzzsaw #1: within our package, we can refer to the component using the standard c: notation. The component was global, so I should be able to use it, right? I also tried c:Offers__ShowOfferConsole, thinking maybe the kind of namespacing you do in Apex would work, but no dice there. Finally I figured it out: outside our package I had to refer to it via its package namespace (which in this case is "Offers"), like this:
<Offers:ShowOfferConsole userId="{!Contact.Id}"/>
Great! That only took me about an hour to figure out! But it still didn't work, now for a different reason. Now I get this error:
Error: Cannot use attribute userid (in component offers:showofferconsole) without global access in a component/page that is not in the same namespace as the component in my_visualforce_page at line 117 column 61
This took a while to track down. The component is global, yes, so I should be able to use it; but in components, like in Apex classes, you also have to make the individual attributes global in order to access them from outside the package. Fortunately this is our own package so we can modify the code, and here we needed to modify the component to make the userId attribute global. Now, finally, I can use the component outside the package!
Monday, June 3, 2013
Assigning Cases According To The Email Address From Which They Originated
Someone asked me an interesting question recently, which was:
I have multiple email addresses that correspond to different divisions of my company. How do I assign cases to these various divisions according to which email address the original email arrived at?
This seemed at first to be a bit of a head-scratcher, since the email address itself is not stored anywhere on the case. However, there is a simple solution: use Case Origin.
Case has a field called Case Origin which can be set on a per-routing-address basis. Our first step, then, will be to set up our Case Origin field to contain the necessary items pertaining to each division. Go to Setup->Customize->Cases->Fields and click the Case Origin link. At the bottom of the page you'll find the Picklist Values. Press the New button to add some entries to this list, one for each division (note that you can add more than one at a time by separating them with a linefeed).
Now go over to Setup->Customize->Cases->Email-To-Case. Click on the Edit link for your Support routing address for each division. At the bottom of the ensuing page, you can set the Case Origin for this routing address. After saving this, you now have a field on Case which records which email address it was created from! You can now use that in your assignment rules. And that's all there is to it.
Oh, and one more thing: if your process requires that you use record types on cases, you can do the exact same trick with the Case Record Type field instead.
I have multiple email addresses that correspond to different divisions of my company. How do I assign cases to these various divisions according to which email address the original email arrived at?
This seemed at first to be a bit of a head-scratcher, since the email address itself is not stored anywhere on the case. However, there is a simple solution: use Case Origin.
Case has a field called Case Origin which can be set on a per-routing-address basis. Our first step, then, will be to set up our Case Origin field to contain the necessary items pertaining to each division. Go to Setup->Customize->Cases->Fields and click the Case Origin link. At the bottom of the page you'll find the Picklist Values. Press the New button to add some entries to this list, one for each division (note that you can add more than one at a time by separating them with a linefeed).
Now go over to Setup->Customize->Cases->Email-To-Case. Click on the Edit link for your Support routing address for each division. At the bottom of the ensuing page, you can set the Case Origin for this routing address. After saving this, you now have a field on Case which records which email address it was created from! You can now use that in your assignment rules. And that's all there is to it.
Oh, and one more thing: if your process requires that you use record types on cases, you can do the exact same trick with the Case Record Type field instead.
Monday, May 27, 2013
The Mass Case Close Button
From time to time, people on the Salesforce.com forums ask how they can make a Mass Case Close button that skips the Case Close screen and just closes the cases directly. This is just a twist on the Quick Case Close button that I have written about previously on this blog. The code is quite simple:
{!REQUIRESCRIPT("/soap/ajax/13.0/connection.js")}
var records = {!GETRECORDIDS($ObjectType.Case)};
if (records[0] == null) {
alert("Please select at least one case to close.")
} else {
//Get more info on the cases that were selected and generate a query out of it
var updateRecords = [];
//Iterate through the returned results
for (var recordIndex=0;recordIndex<records.length;recordIndex++) {
var caseUpdate = new sforce.SObject("Case");
caseUpdate.Id = records[recordIndex];
caseUpdate.Status = 'Closed';
updateRecords.push(caseUpdate);
}
var result = sforce.connection.update(updateRecords);
//handle errors here
if (result.error) {
alert('There was an error processing one or more cases');
}
//Reload the list view to show what he now owns
parent.window.location.reload();
}
To add this code, go to Setup->Cases->Buttons and Links and make a new custom button called Mass Close. Its Display Type should be set to List Button, its Behavior to Execute JavaScript, and its Content Source to OnClick JavaScript. Paste the above code into the OnClick JavaScript field -- but be sure to replace the caseUpdate.Status = 'Closed'; line with a status that is present in your org.
Now you'll have to add this button to the Case list view. To do this, go to Setup->Cases->Search Layouts. Click Edit next to the Cases List View entry, and add your new button from the Available Buttons section to the Selected Buttons section. As with the Contention-Proof Accept Button, the trick here is that GETRECORDIDS call -- it gets us the list of Case IDs that you selected from the list. The rest here is simple, just put all those Case IDs into an array and set the case status fields to Closed, and call update. Easy! Just imagine what other sorts of mass actions you could do with this method. It's hard to fathom the creativity of the readers of this blog.
{!REQUIRESCRIPT("/soap/ajax/13.0/connection.js")}
var records = {!GETRECORDIDS($ObjectType.Case)};
if (records[0] == null) {
alert("Please select at least one case to close.")
} else {
//Get more info on the cases that were selected and generate a query out of it
var updateRecords = [];
//Iterate through the returned results
for (var recordIndex=0;recordIndex<records.length;recordIndex++) {
var caseUpdate = new sforce.SObject("Case");
caseUpdate.Id = records[recordIndex];
caseUpdate.Status = 'Closed';
updateRecords.push(caseUpdate);
}
var result = sforce.connection.update(updateRecords);
//handle errors here
if (result.error) {
alert('There was an error processing one or more cases');
}
//Reload the list view to show what he now owns
parent.window.location.reload();
}
To add this code, go to Setup->Cases->Buttons and Links and make a new custom button called Mass Close. Its Display Type should be set to List Button, its Behavior to Execute JavaScript, and its Content Source to OnClick JavaScript. Paste the above code into the OnClick JavaScript field -- but be sure to replace the caseUpdate.Status = 'Closed'; line with a status that is present in your org.
Now you'll have to add this button to the Case list view. To do this, go to Setup->Cases->Search Layouts. Click Edit next to the Cases List View entry, and add your new button from the Available Buttons section to the Selected Buttons section. As with the Contention-Proof Accept Button, the trick here is that GETRECORDIDS call -- it gets us the list of Case IDs that you selected from the list. The rest here is simple, just put all those Case IDs into an array and set the case status fields to Closed, and call update. Easy! Just imagine what other sorts of mass actions you could do with this method. It's hard to fathom the creativity of the readers of this blog.
Thursday, May 23, 2013
The Quick Case Close Button
People often ask me how they can get around the Close Case page. One option to do this is to replace the standard Close Case button with a custom button of your own. It's remarkably easy to do! Here's how.
First, go to Setup->Cases->Buttons and Links and make a new custom button called Close Case. Its Display Type should be set to Detail Page Button, its Behavior to Execute JavaScript, and its Content Source to OnClick JavaScript.
Now you need only paste the following JavaScript in there:
{!REQUIRESCRIPT("/soap/ajax/13.0/connection.js")}
var caseObj = new sforce.SObject("Case");
caseObj.Id = '{!Case.Id}';
caseObj.Status = 'Closed';
var result = sforce.connection.update([caseObj]);
if (result[0].success=='false') {
alert(result[0].errors.message);
} else {
location.reload(true);
}
This is assuming, of course, that you actually have a status called "Closed" -- but if you don't, don't despair -- just change the caseObj.Status = 'Closed'; line to a closed status that actually exists in your case status list.
Now edit your Case page layout. Click on the Detail Page Buttons box and it will be highlighted, then click the Edit Properties button. Here you'll be able to hide the standard Close Case button and show your new custom Close Case button. Finally test your new button by making a test case and closing it. Voila! The button sets the case to a closed status and reloads the page to give you feedback that in fact it was closed!
Please note that because this trick uses the API, it will only work for Enterprise Edition and up, or for Professional Edition with the API add-on.
First, go to Setup->Cases->Buttons and Links and make a new custom button called Close Case. Its Display Type should be set to Detail Page Button, its Behavior to Execute JavaScript, and its Content Source to OnClick JavaScript.
Now you need only paste the following JavaScript in there:
{!REQUIRESCRIPT("/soap/ajax/13.0/connection.js")}
var caseObj = new sforce.SObject("Case");
caseObj.Id = '{!Case.Id}';
caseObj.Status = 'Closed';
var result = sforce.connection.update([caseObj]);
if (result[0].success=='false') {
alert(result[0].errors.message);
} else {
location.reload(true);
}
This is assuming, of course, that you actually have a status called "Closed" -- but if you don't, don't despair -- just change the caseObj.Status = 'Closed'; line to a closed status that actually exists in your case status list.
Now edit your Case page layout. Click on the Detail Page Buttons box and it will be highlighted, then click the Edit Properties button. Here you'll be able to hide the standard Close Case button and show your new custom Close Case button. Finally test your new button by making a test case and closing it. Voila! The button sets the case to a closed status and reloads the page to give you feedback that in fact it was closed!
Please note that because this trick uses the API, it will only work for Enterprise Edition and up, or for Professional Edition with the API add-on.
Monday, May 20, 2013
The Quick Email Button Revisited: Sending One-And-Done Emails with Workflow
In my popular post The Quick Email Button I reference a means of making a button that just sends the email immediately with no edit window. I then mention that it's been deprecated for orgs that have been created since 2010.
Salesforce.com deprecated this URL parameter for a good reason: the save=1 parameter is not particularly secure, and a clever attacker could make spoofed links to Salesforce.com to save random data to your org. I will say this about URL hacks in general: they are hacks, and that makes them inherently unreliable. Sometimes they will stop working. So despite my tacit encouragement in my original post, try not to use them if you can avoid them.
The question remains, then:
How can you make a button that sends a one-and-done email?
This simple but roundabout method uses Workflow email alerts and a Javascript custom button. Note that this method uses the Salesforce.com API, so it will only work with orgs that have the API (generally Enterprise Edition and above, or Professional Edition with the API add-on). Here's how to do it:
1. Make a custom checkbox field on your object called "Send Email." Don't show it on any page layouts -- it should only be used as a proxy for the workflow we'll define below.
2. Make a new workflow rule on this object and set it to run when a record is "created, and any time it’s edited to subsequently meet criteria." Change the Rule Criteria to run if the "formula evaluates to true," and in the formula box, enter ISCHANGED(Send_Email__c).
3. Press Next and add an Email Alert that selects the proper template and sends to the person you want to send to (generally the email address of the Lead or Contact you're putting the button on). Save the email alert. Don't forget to activate your workflow rule!
4. Now go to your object and create a custom button on it. Set this custom button to Execute Javascript, and put code in that looks like this (the below example is for the Lead object, you'll need to modify it slightly for any other object type):
{!REQUIRESCRIPT("/soap/ajax/16.0/connection.js")}
var leadObj= new sforce.SObject("Lead");
leadObj.Id='{!Lead.Id}';
//Update that checkbox to true, which will trigger the workflow
leadObj.Send_Email__c = true;
var result=sforce.connection.update([leadObj]); /*updating the object*/
if (result[0].success=='false') {
alert(result[0].errors.message);
} else {
location.reload(true);
}
5. Add this custom button to your page layouts.
And voila! You now have a custom button that immediately sends out an email without any further user intervention.
There's another way to do this with just a custom button alone and no workflow, but it's a bit more involved on the code side. I'll cover that in a future post on this topic.
Happy emailing!
Salesforce.com deprecated this URL parameter for a good reason: the save=1 parameter is not particularly secure, and a clever attacker could make spoofed links to Salesforce.com to save random data to your org. I will say this about URL hacks in general: they are hacks, and that makes them inherently unreliable. Sometimes they will stop working. So despite my tacit encouragement in my original post, try not to use them if you can avoid them.
The question remains, then:
How can you make a button that sends a one-and-done email?
This simple but roundabout method uses Workflow email alerts and a Javascript custom button. Note that this method uses the Salesforce.com API, so it will only work with orgs that have the API (generally Enterprise Edition and above, or Professional Edition with the API add-on). Here's how to do it:
1. Make a custom checkbox field on your object called "Send Email." Don't show it on any page layouts -- it should only be used as a proxy for the workflow we'll define below.
2. Make a new workflow rule on this object and set it to run when a record is "created, and any time it’s edited to subsequently meet criteria." Change the Rule Criteria to run if the "formula evaluates to true," and in the formula box, enter ISCHANGED(Send_Email__c).
3. Press Next and add an Email Alert that selects the proper template and sends to the person you want to send to (generally the email address of the Lead or Contact you're putting the button on). Save the email alert. Don't forget to activate your workflow rule!
4. Now go to your object and create a custom button on it. Set this custom button to Execute Javascript, and put code in that looks like this (the below example is for the Lead object, you'll need to modify it slightly for any other object type):
{!REQUIRESCRIPT("/soap/ajax/16.0/connection.js")}
var leadObj= new sforce.SObject("Lead");
leadObj.Id='{!Lead.Id}';
//Update that checkbox to true, which will trigger the workflow
leadObj.Send_Email__c = true;
var result=sforce.connection.update([leadObj]); /*updating the object*/
if (result[0].success=='false') {
alert(result[0].errors.message);
} else {
location.reload(true);
}
5. Add this custom button to your page layouts.
And voila! You now have a custom button that immediately sends out an email without any further user intervention.
There's another way to do this with just a custom button alone and no workflow, but it's a bit more involved on the code side. I'll cover that in a future post on this topic.
Happy emailing!
Friday, May 17, 2013
Next Best Activity, Cross-sell and Upsell in Salesforce.com
I would be remiss if I didn't at least occasionally mention some of the stuff I'm doing now at KXEN, particularly since much of it is very much complementary to Salesforce.com's current offering.
First: for those who want to hear the werewolf's dulcet tones live, I'll be doing a webinar on this topic on May 29, 2013 -- register here.
Before I came to KXEN, I was in the call center world for over five years, and one of the most common things I heard is that the people who run those call centers want to be able to make effective offers to prospects (in telesales call centers), and upsell and cross-sell their existing customers (primarily in customer service call centers).
Until recently, the only real option for delivering these types of offers in Salesforce.com in the call center was to build a custom offer system. Many Salesforce.com users do just that, using Visualforce, Apex and a rudimentary set of rules, and it can be quite painful.
We have recently released Predictive Offers to solve this problem. Predictive Offers is a self-learning offer system, meaning that rather than making you code up a bunch of rules to decide what to offer to whom, it learns from your prospects' and customers' history and applies what it has learned to make a decision as to the best offer to make. On top of that, Predictive Offers still allows you to apply certain rules to "clarify" its decisions. For instance, some companies may want to apply an "already has" rule -- a printer company might offer you a toner cartridge even if they've sold you one in the past, but your cable company shouldn't offer you HBO if you already have HBO! Predictive Offers supports that type of logic. It's Force.com-native, so it works right inside Salesforce.com, and it's specifically made to be as easy to administer as Salesforce.com itself. It works with both the Sales Cloud (in the standard Salesforce.com interface) and the Service Cloud (in the Service Cloud Console).
Check it out at the embedded YouTube video here, or even better, give it a spin with a free trial from our Predictive Offers AppExchange page.
First: for those who want to hear the werewolf's dulcet tones live, I'll be doing a webinar on this topic on May 29, 2013 -- register here.
Before I came to KXEN, I was in the call center world for over five years, and one of the most common things I heard is that the people who run those call centers want to be able to make effective offers to prospects (in telesales call centers), and upsell and cross-sell their existing customers (primarily in customer service call centers).
Until recently, the only real option for delivering these types of offers in Salesforce.com in the call center was to build a custom offer system. Many Salesforce.com users do just that, using Visualforce, Apex and a rudimentary set of rules, and it can be quite painful.
We have recently released Predictive Offers to solve this problem. Predictive Offers is a self-learning offer system, meaning that rather than making you code up a bunch of rules to decide what to offer to whom, it learns from your prospects' and customers' history and applies what it has learned to make a decision as to the best offer to make. On top of that, Predictive Offers still allows you to apply certain rules to "clarify" its decisions. For instance, some companies may want to apply an "already has" rule -- a printer company might offer you a toner cartridge even if they've sold you one in the past, but your cable company shouldn't offer you HBO if you already have HBO! Predictive Offers supports that type of logic. It's Force.com-native, so it works right inside Salesforce.com, and it's specifically made to be as easy to administer as Salesforce.com itself. It works with both the Sales Cloud (in the standard Salesforce.com interface) and the Service Cloud (in the Service Cloud Console).
Check it out at the embedded YouTube video here, or even better, give it a spin with a free trial from our Predictive Offers AppExchange page.
Thursday, May 16, 2013
How To Stop People From Making Comments On Closed Cases
Sometimes people ask me how they can make closed cases "uncommentable" -- once those cases are closed, they don't want their reps to be able to make new comments on them. Traditionally the way to accomplish this would be to change the record type of closed cases and use a layout for that record type which hides the Case Comments related list.
This is not ideal, though, because it means that you can't read the comments either. Fortunately, with Workflow From Case Comments, there is a better way. As I mentioned in my previous blog entry, Workflow From Case Comments is a "chaining" workflow, which means that when it edits the parent case, it kicks off the workflow anew on that case object. We can use this to our advantage in solving this problem. Here's how.
Workflow From Case Comments to the rescue!
This is not ideal, though, because it means that you can't read the comments either. Fortunately, with Workflow From Case Comments, there is a better way. As I mentioned in my previous blog entry, Workflow From Case Comments is a "chaining" workflow, which means that when it edits the parent case, it kicks off the workflow anew on that case object. We can use this to our advantage in solving this problem. Here's how.
- Define a checkbox-type custom field on Case called "No more comments." Do not add it to any of the Case page layouts.
- Make a validation rule which shows the error "You cannot add comments to a closed case" at the top of the page. In the formula section put simply "No_more_comments__c=true".
- Make a Workflow on the Case Comments object which fires when Case: Closed equals True.
- Make a Field Update in that workflow which sets the No More Comments field to true.
- Activate the workflow rule!
Workflow From Case Comments to the rescue!
Wednesday, May 15, 2013
The Quick Email Button
...or, mastering the black art of URL hacking the email page.
Sending an email from Salesforce.com can be a clicky operation. You dig around for the Send An Email button, click it, click Select Template, find your template and click it, maybe type some more stuff in the email, and finally click Send. That's a lot of clicks, especially for organizations where they just use the same template over and over. Well, the good news is that you can make this a much less clicky operation by making a custom button which changes the URL parameters. Technically URL-hacking is not supported by Salesforce.com, and it's technically not a supported API, so be forewarned -- but when you're on a quest to reduce clicks, you gotta do what you gotta do.
So let's say you have a template that you usually use for Cases which contains some pleasantries and then a merge field that adds in the text of any related Solutions. If you've not used Email Templates much before, by the way, have a look at the sample template entitled "SUPPORT: Case Response with Solution (SAMPLE)" -- it does just what I've described here. Anyway, what you'll want to do is make a custom button that preselects this template. It's quite simple really.
- The first thing you'll need to do is get the ID of the template you want to use. This can be found by finding the template via Setup->Communication Templates->Email Templates. Click on it and look in the URL -- you'll see an ID up there that looks like 00X30000000rNM0 (which may be followed by a ? with some other parameters -- ignore that stuff, just take the 15-character ID that starts with 00X). Copy that ID into Notepad or someplace where you can get to it later.
- Now go to Case and create a Custom Button -- let's call it Email Solution. Set its Behavior to Execute Javascript and its Display Type to Detail Page Button. In the Javascript area add this line of code, replacing the <your template here> with the ID of the template you saved earlier: location.replace('/email/
author/emailauthor.jsp?retURL= /{!Case.Id}&p3_lkid={!Case.Id} &rtype=003&p2_lkid={!Case. ContactId}&template_id=<your template here>');
- Now add this custom button to your Case page layout, and voila, you have a one-click button that will bring up your email complete with template.
But wait, there's more!
To this we can actually add a few more bells and whistles.
By default the Send An Email page likes to BCC the sender. Many call center agents I talk to find this rather annoying. With the addition of another URL parameter to our custom button, we can stop it from BCCing anyone. The parameter is p5, so our new code would be:
location.replace('/email/ author/emailauthor.jsp?retURL= /{!Case.Id}&p3_lkid={!Case.Id} &rtype=003&p2_lkid={!Case. ContactId}&template_id=<your template here>&p5=');
location.replace('/email/
Notice at the end there the "&p5=" -- that sets the BCC area to empty.
But what if you just want to send the email in one click with no edits?
Well, you can do that too, with -- you guessed it -- one more URL parameter: the save parameter. If I take the above code and add a save=1 to it, then when I click the button, the email will just be sent, and the Case page will refresh itself to indicate that an email was sent:
location.replace('/email/ author/emailauthor.jsp?retURL= /{!Case.Id}&p3_lkid={!Case.Id} &rtype=003&p2_lkid={!Case. ContactId}&template_id=< yourtemplate here>&p5=&save=1');
Note that this parameter only works for long-established Salesforce.com orgs -- for new orgs the save=1 parameter is disabled for security reasons. If you have a newer org (created in 2010 or later) then you should use the AJAX Toolkit to send the email. That will be the subject of a future blog post here.
What if you want to add some email addresses to Additional To?
Easy enough, that's p24.
location.replace('/email/
Note that this parameter only works for long-established Salesforce.com orgs -- for new orgs the save=1 parameter is disabled for security reasons. If you have a newer org (created in 2010 or later) then you should use the AJAX Toolkit to send the email. That will be the subject of a future blog post here.
What if you want to add some email addresses to Additional To?
Easy enough, that's p24.
And what if you want to change the From address?
You may have noticed that if you have Email To Case enabled with some routing addresses, or if you've modified the email address in the My Email Settings page in the Personal Information area of Setup, that when you go to send an email you have a choice of From addresses. You can default this From address too!
The From address is just another parameter in the URL -- it's p26. So taking our earlier example, let's add a From address default:
location.replace('/email/ author/emailauthor.jsp?retURL= /{!Case.Id}&p3_lkid={!Case.Id} &rtype=003&p2_lkid={!Case. ContactId}&template_id=< yourtemplate here>&p26=me@mydomain.com');
location.replace('/email/
Note that the p26 default will only work for items that are actually in that From address list.
And that ends today's lesson on email buttons.
Happy emailing!
Happy emailing!
Subscribe to:
Posts (Atom)