Sunday, October 6, 2013

Salesforce CTA Part 2 Exam - Study Materials

A number of people have followed up with me after my earlier post on the exam about what are some of the study materials I used to prepare for the exam. To be perfectly honest, I didn't get a chance to read and review everything that I wanted to before taking the exam but I have been gathering a lot of reference material over time which I regularly reviewed and it helped when preparing for the exam. Most of them are presentations from Dreamforce '12 sessions which are available from the Salesforce Channel in YouTube and the rest are mostly articles or blogs on the developerforce.com site.

I grouped the materials into a few general areas which I think are very essential. These include (in no particular order of importance):

  • Force.com Platform
  • Platform Security
  • Integration
  • Large Data Volume Considerations
  • Single vs Multi-Org Strategy
  • Force.com Development
  • Deployment and Governance 

Again, these are just a few of the important topic areas and you should refer to the objectives in the Study Guide for the complete list.

I would highly recommend starting with this video from Dreamforce '12 which provides a good discussion around what is involved in getting the Technical Architect Certification.
http://www.youtube.com/watch?v=G2fOP7MKb6A

Force.com Platform:

The Force.com Multitenant Architecture
http://wiki.developerforce.com/page/Multi_Tenant_Architecture

Understanding Force.com Platform Internals Helps You Build Better Apps
http://blogs.developerforce.com/engineering/2013/04/understanding-force-com-platform-internals-helps-you-build-better-apps.html

Record-Level Access: Under the Hood
http://www.salesforce.com/docs/en/cce/record_access_uth/salesforce_record_access_under_the_hood.pdf

Designing Record Access for Enterprise Scale
http://www.salesforce.com/docs/en/cce/draes/draes.pdf

Platform Security:

Security Implementation Guide
http://www.salesforce.com/us/developer/docs/securityImplGuide/index.htm

A Guide to Sharing Architecture
https://na1.salesforce.com/help/doc/en/sharing_architecture.pdf

Taking a Pragmatic Look at the Salesforce Security Model

Security & Sharing Overview - You Hold the Keys
http://www.youtube.com/watch?v=UsX6mah9oKc

Managing the Role Hierarchy at Enterprise Scale
http://www.youtube.com/watch?v=FLXbt34cobg

Single Sign-On Best Practices
http://www.youtube.com/watch?v=8qTr4ulS-WU

Single Sign On with SAML
http://wiki.developerforce.com/page/Single_Sign-On_with_SAML_on_Force.com

OAuth the Big Picture
http://info.apigee.com/Portals/62317/docs/oauth_big_picture.pdf

Digging Deeper into OAuth 2.0 on Force.com
http://wiki.developerforce.com/page/Digging_Deeper_into_OAuth_2.0_on_Force.com

Single Sign-On for Desktop and Mobile Applications using SAML and OAuth
http://wiki.developerforce.com/page/Single_Sign-On_for_Desktop_and_Mobile_Applications_using_SAML_and_OAuth

You need to know all the OAuth and SAML flows in detail -- this is a MUST!

Integration:

Integration Wiki Page
http://wiki.developerforce.com/page/Integration

Integrating with the Force.com Platform

Large Data Volume Considerations:

Large Data Volume Deployments - Best Practices
http://www.youtube.com/watch?v=jgNlTMrox7g

Managing Large Data Volumes - Best Practices for Data Efficiency
http://www.youtube.com/watch?v=nrBqGkTBxMI

Extreme Salesforce Data Volumes
http://wiki.developerforce.com/page/Webinar:_Extreme_Salesforce_Data_Volumes_(2013-Feb)

Database Query and Search Optimization Cheat Sheet
http://s3.amazonaws.com/dfc-wiki/en/images/0/0e/Db-query-search-optimization-cheat-sheet.pdf

Best Practices for Deployments with Large Data Volumes:
http://wiki.developerforce.com/page/Best_Practices_for_Deployments_with_Large_Data_Volumes

Designing Dashboards and Reports for Force.com Implementations with Large Data Volumes
http://blogs.developerforce.com/engineering/2013/08/designing-dashboards-and-reports-for-force-com-implementations-with-large-data-volumes.html

Architect Salesforce Record Ownership Skew for Peak Performance in Large Data Volume Environments
http://blogs.developerforce.com/engineering/2012/06/architect-salesforce-record-ownership-skew-for-peak-performance-in-large-data-volume-environments.html

Reducing Lock Contention by Avoiding Account Data Skew
http://blogs.developerforce.com/engineering/2013/01/reducing-lock-contention-by-avoiding-account-data-skews.html

Working with Very Large SOQL Queries
http://www.salesforce.com/us/developer/docs/apexcode/Content/langCon_apex_SOQL_VLSQ.htm

Webinar: Inside the Force.com Query Optimizer
http://wiki.developerforce.com/page/Webinar:_Inside_the_Force.com_Query_Optimizer_(2013-Apr)

Maximizing the Performance of Force.com SOQL, Reports, and List Views
http://blogs.developerforce.com/engineering/2013/07/maximizing-the-performance-of-force-com-soql-reports-and-list-views.html

Single vs Multi-Org Strategy:

Why Single Org?
- 360 degree view and reporting
- Global forecasting
- Up-sell and cross-sell
- Collaboration
- Standardize Processes
- Support

Why Multi-Org?
- Legacy
- multiple businesses acquired through acquisitions
- Independent Business Units
- business units run independently of each other
- Functional
- different business processes - hr and sales
- Legal
- tax laws, compliance
- Org Limits
- salesforce governor limits, workflow, dashboard number limits
- Geographic/Language
- different regions are autonomous (US/ EMEA)

Single or Multi-org: What's Right for My Deployment?

What is the Right Org Architecture Strategy for your Enterprise?

Thinking Differently about Orgs

Force.com Development:

Salesforce Development Lifecycle Guide
http://www.salesforce.com/us/developer/docs/dev_lifecycle/salesforce_development_lifecycle.pdf

Triggers and Order of Execution
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_triggers_order_of_execution.htm

Apex Design Patterns
http://www.youtube.com/watch?v=J372XmYds-A

Applying Enterprise Application Design Patterns on Force.com
http://www.slideshare.net/afawcett/df12-applying-enterprise-application-design-patterns-on-forcecom

Deploying Salesforce Globally
http://www.slideshare.net/Salesforce/deploying-salesforce-globally

Deployment and Governance:

Continuous Delivery with Force.com
http://www.youtube.com/watch?v=xeG5SonUuA8

Release Management for Large Organizations
http://www.youtube.com/watch?v=_3YeKq00a8I

Agile Release Management in a Large Enterprise
http://www.youtube.com/watch?v=mp8mgPQNOwg

Change and Release Management: Developing A Plan That Works For You
http://www.youtube.com/watch?v=czLxAa7XkS4

Performance Monitoring and Testing the Salesforce Cloud
http://www.youtube.com/watch?v=x2Jja81xxkE

As you can tell from just looking at the titles, even if you are not planning to take the exam any time soon, reviewing these materials in detail will give you a much better insight into the force.com platform and it's capabilities. Good luck!

Implementing a Stack in Apex

Apex collections comprise of Set, List and Map types and really nothing else. If you come from a Java or .Net background this must seem quite limiting at first given the variety of collections they support. However, in a metadata driven platform such as force.com you shouldn't have to worry about the nuances of a HashMap versus a Hashtable -- you just use a Map data structure and it is automatically optimized for you by the platform. As much as I like the simplicity of the force.com Apex programming I do miss some of the collection types that I have gotten used to in Java such as TreeMap, TreeSet and Stacks which can simplify the programming quite a bit.

Recently there was a need to implement a trigger logic which although could have been done using a List, was more appropriate for the use of a Stack. So I wrote a basic Stack class and sure enough it made the rest of the implementation a lot cleaner. There are really only three basic operations for a Stack -- push() to add an item on to the stack, pop() to remove the most recent (top most) item from the stack and peek() to take a look at the top most item without removing it from the stack. We can also add a size() method to return the number of items currently in the stack and an isEmpty() method to check if the stack is empty. You could optionally implement an iterator to iterate through the Stack but that is left as an exercise for the reader (no, you can't simply expose the List iterator :).

So here is the classic Stack implemented in Apex using the List.

public class Stack {
    private List<Object> items {get; set;}
    
    public Stack() {
        this.items = new List<Object>();
    }
    
    public Integer size() {
        return this.items.size();
    }

    public Boolean isEmpty() {
        return size() == 0;
    }
        
    public void push(Object itemToPush) {
        this.items.add(itemToPush);
    }
    
    public Object pop() {
        if (isEmpty()) {
            throw new StackUnderflowException();
        }
        
        return this.items.remove(size() - 1);
    }
    
    public Object peek() {
        if (isEmpty()) {
            throw new StackUnderflowException();
        }
        
        return this.items.get(size() - 1);
    }    
}

If we try to peek or pop from an empty stack, we would get an StackUnderflowException, which is a custom exception class: 

public class StackUnderflowException extends Exception {
    /* Custom exception */
}

That's pretty much it! Now you can use it for all sorts of LIFO (Last In First Out) type functions such as evaluating expressions or parsing a syntax tree. 

Stack s = new Stack();
s.push(10.0);
s.push(5.0);
s.push('+');

while (!s.isEmpty()) {
    Object o = s.pop();

    if (String.valueOf(o) == '+') {
        Double d1 = Double.valueOf(s.pop());
        Double d2 = Double.valueOf(s.pop());
        Double result = d1 + d2;
        System.Debug(d1 + ' + ' + d2 + ' = ' + result);
    } 
}

It should print:
5.0 + 10.0 = 15.0

Happy Stacking!

Friday, September 27, 2013

SAML Explained

So what is SAML? Well SAML stands for Security Assertion Markup Language and has become the predominant way that enterprises perform internet based Single Sign On (SSO) these days. Its been around for a while and there is plenty of documentation online that explains how it works. Still somehow every time I talk to someone about SAML and SSO, there is always some confusion. So here is an attempt at explaining the basic SAML flow in terms that you can hopefully remember.

Let's say that your rising kindergartner wants to join the soccer practice at school, what does he do? He goes to the teacher and asks if he could join the soccer practice. The teacher hands him a piece of paper and says please have your parents fill out this form and have them sign it. The kid brings that piece of paper to the parents, they look at it, consider his request, fill out the form, sign it and give it back to him, asking him to take it back to the teacher without messing with it. The kid takes the completed and signed form back to the teacher, who verifies it and lets the kid join the soccer practice. At the basic level this is exactly how SAML works -- just substitute the User for the kid, a Service Provider (SP) for the school teacher and an Identity Provider (IdP) for the parents.

Now, don't over think the analogy or expand too much upon it, I'm sure you can poke some holes; just use it to remember the basic flow of information. 

When the User tries to access a protected resource at the Service Provider, the SP will check the user's domain and will generate a SAML Request redirecting the user to the Organization's Identity Provider. The IdP will verify the identity of the user (by way of login, if not already logged in) and will generate a SAML Assertion (containing a Federated ID) and send a SAML Response back to the SP. The SP will verify the SAML Assertion (the Federated ID), log the user in and will provider access to the protected resource. Now, in all these different redirects the original URL to the protected resource that the User was trying to access will be preserved and passed in as the Relay State (not directly as a URL, but as some binding to it). Once logged in (after verifying the SAML Assertion), the SP will forward the User to the original request URL as maintained in the Relay State. Here is a picture of the flow (borrowed from article referenced below):

Saml flow.png
SAML 2.0 - Service Provider Initiated SSO

The above flow is known as the Service Provider initiated SSO in which the user first tries to access a resource at the SP and initiates the flow. A variation of this is the IdP initiated SSO where the user would login at the IdP and will click on a link to access the Service Provider. In that case, the IdP would generate the SAML Assertion when the user clicks on the Service Provider link and will take the user to the start page configured for the Service Provider. This start page at the SP should know how to validate the Assertion, automatically login the user and redirect to the home page. There is no Relay State involved here. 

The key to all this is that the Service Provider and Identify Provider have already established a trust relationship by setting up the required information, importing certificates, etc. at the time of setup -- similar to how the kid's school knows that you are the parent by requesting for the child's birth certificate, completed and signed forms etc. at the time of registration :) 

To understand in depth how SSO with SAML works in Salesforce.com, check out: 

For setting up SSO in Salesforce.com, along with examples of SAML Request and Response, Just In Time Provisioning, etc., check out the SSO Implementation Guide:
http://login.salesforce.com/help/doc/en/salesforce_single_sign_on.pdf

Finally, for setting up SSO for Desktop and Mobile apps with Salesforce, check out:
http://wiki.developerforce.com/page/Single_Sign-On_for_Desktop_and_Mobile_Applications_using_SAML_and_OAuth

Enjoy!

Sunday, September 22, 2013

Salesforce Certified Technical Architect - Part 2 Exam

This weekend I cleared the Salesforce Technical Architect certification part 2 exam and wanted to share my experience along with some tips and tricks. First of all, it's a great exam to take because of the breadth and depth of topics covered. As a technical architect you work on a number of areas over the years such as requirements gap analysis, technical architecture, design and development, deployments, data migrations, performance tuning and troubleshooting, SSO, Web Services, SSL, firewalls, etc. and in preparing for the exam you will need to recollect a lot of that experience and something like remembering the difference between 2nd and 3rd normal forms can come in quite handy (if you are wondering what are "normal forms", then you have some studying to do :) 

Now, if you are just starting to prepare then the first place to look of course is the official Study Guide and especially Section 5: Recommended Training and References. One of the first things recommended there is the Dev 401 training and if you are pursuing the Architect certification you must have cleared the Dev 401 exam and should be well aware of the basics anyway. If you happen to be Dev 501 certified (or trained) it's certainly beneficial but you don't have to be and having hands-on experience working with Apex and Visualforce will do just fine. Integration is another key area and the Dev 502 training I'm sure is quite useful but you can also refer to the online documentation and get enough information. Again, hands-on experience is a must because there were several questions around integration that required a lot of thought to answer. The rest of the resources refer to either online courses, webinars or technical articles - all of which are very good to know and highly recommended. 

The next section in the guide - Section 6: Exam Outline - is IMO the most important section that you need to focus on. If you can read through the objectives and feel like yeah ok I get this, then you are in good shape. If you are not aware of some of the concepts, then try to focus on those depending on how much weight is assigned. For example a fourth of the exam is about Platform Architecture concepts - which means you should know about a broad range of concepts and details around Salesforce and force.com Platform, such as how force.com multi-tenant architecture works, what are the different types of licenses and their nuances, the differences between going with a single-org or multi-org strategy, large data volume considerations, i18n capabilities, etc. If you have read through this section of the guide, my recommendation is, please re-read it and make sure you understand _every_ one of the objectives. 

The exam is 60 questions, multiple choice and you have two hours to complete. Most of the questions are quite long (6-8 sentences) and for a majority of them you have to choose 2 or 3 correct options out of 5. I would say the questions where you have to choose 3 correct answers are relatively easy compared to the ones where you had 2 correct choices because it is easier to eliminate the two wrong ones than to pick two right ones. A good number of them required re-reading the question and choices several (>3) times, the rest I was able to get through mostly in one speed reading (or two). I was stumped on very few (say 3 or 4) because they were quite specific and I just didn't know the answer and ended up guessing (I checked them after I got home and sure enough I had them all wrong :) 

Also you have to keep an eye on the clock because time just flies. I got through only about 7 or 8 questions in the first 25 minutes (ramp up time I guess!) but still managed to finish the exam with around 15 mins to spare and review some answers. So the key is if you have to re-read a question and still can't figure out the choices its best to just mark it for review and come back to it at the end. Otherwise you might miss out on some easy ones. The other thing is when you are stuck between two choices the answer is usually based on one or two key words in the question so you might have to just review it quickly again. Also be sure to read ALL the choices (especially for the one or two correct choices) as there can be subtle differences in the choices. I say this because I didn't find any question to be ambiguous and felt pretty comfortable with my answer choices after I reviewed them. Overall it was a good experience and wasn't as bad as I had expected. 

Good luck with the preparation!

UPDATE: Refer to the follow up post for references to the study materials.

Tuesday, November 8, 2011

Creating Outlook Appointments from Email

I'm sure everyone who uses Outlook runs into this issue of creating a meeting invite based on an email that was just received. I'm surprised Microsoft hasn't added a button by default to make it easy, but just because it's not there doesn't mean it's not possible. (Another reason to switch to Gmail, it's two clicks away - should really be one click away, but then ...)

The quick and dirty way to do it is to just drag the message onto the calendar tab and it will automatically open up an appointment for the next hour with the message in the body of the invite. What it doesn't do is to add the people on the email to the invitees list - you still have to add them manually. Now, we don't want to do that, do we? A VBA macro ought to do it. Thankfully, you don't have to write that yourself (unless you suffer from a serious case of NIH syndrome), as someone (who works for Microsoft in this case) has already done this for you - a few years ago!

The quick steps are:

  1. Download this file (it's safe don't worry) and save it to your Desktop: http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-components-postattachments/00-02-50-65-92/NewMeetingRequestFromEmail.bas
  2. Open Outlook, hit Alt-F11 to open the Visual Basic Editor
  3. Hit Ctrl-M to open the import dialog and select the downloaded file to import. Save and close. 
  4. Open any email and from the quick access toolbar, hover over an item and right click to select "Customize Quick Access Toolbar ..." 
  5. In the configuration pop-up window, select "Macros" from the "Choose commands from: " drop-down menu. 
  6. You should see the macro that you just saved there, click "Add >>" to add it to the Quick Access Toolbar. (Choose a different icon to make it look like a Calendar to satisfy your inner OCD)
Now, when you open any message you can simply click this icon and it will do all wonderful things for you:
  • Create a new appointment
  • Copy the categories, body, and subject
    • Copy the attachments
      • Add the sender as a meeting participant
        • Add each email recipient as a meeting participant
          • Each To: participant will be required
          • Each CC: or BCC: participant will be optional

        If you would like more detailed instructions, then please refer to the original blog posts about how to get this done:

        Creating an Outlook Appointment based on an Email message
        Adding a VBA Macro to Outlook

        Enjoy!

        Monday, October 3, 2011

        Google Apps Script - Save Gmail attachments to Salesforce

        I recently signed up for Salesforce's force.com developer account to play around with it. It's a rather impressive platform and they recently announced full REST API support. I wanted to see how easy it was to integrate something using this API and decided to create an utility that would save some important Gmail attachments to Salesforce. Seemed like a good fit for using Google Apps Script as well, which recently added support for Gmail.

        Disclaimer: There may already be better ways to do this - I never checked because it is not my intent to create an utility for general public use, I merely want to learn the usage of the APIs. However, if it seems like something you could use, feel free to copy. Of course use it at your own risk and the usual yada-yada applies.

        Ok, first of all I don't want all my attachments being saved in SF and hence I'm going to filter only those that are sent to "username+Salesforce@gmail.com" - the idea being if it's something important then I would forward it to my address adding the +Salesforce tag. The +tag in Gmail address is one way to do this, you can setup some labels, filters, etc. if you like.

        The steps to do this automation are:

        1. Register a Remote Application in Salesforce
        2. Create a new Folder in Salesforce for saving the documents
        3. Create a Google Apps Script  
        4. Do a dry run (unit test!) 
        5. Set it up on a timer trigger

        Now, lets go through it step by step:

        Step 1: Register a Remote Application Salesforce
        Follow the instructions here to register a remote application - https://na12.salesforce.com/help/doc/en/remoteaccess_define.htm.
        Be sure to name it "Gmail2Salesforce" for consistency. I guess it doesn't matter what you call it, you just need the keys.

        Step 2: Create a new Folder in Salesforce for saving the documents
        Create a Folder under Documents tab called "From Gmail" - if you use something else be sure to update it in the script.

        Step 3: Create a Google Apps Script
        Like all things Google, it is still evolving but there is plenty of documentation at http://code.google.com/googleapps/appsscript/
        a. Go to docs.google.com
        b. Create new Spreadsheet
        c. Go to Tools -> Script Editor
        d. Copy paste the source code below and save it as "Gmail2Salesforce"
        e. Open the Properties dialog from File menu and create two new Project Properties named ConsumerKey and ConsumerSecret. The values for which have to come from the screen in step 1 where you registered this app in Salesforce.

        Step 4: Do a dry run (unit test!)
        To do a dry run first send a test email to your Gmail address with the +tag, i.e., username+Salesforce@gmail.com - with some attachment obviously.

        a. In the "Select function" drop-down in Script Editor, select "myFunction" and click the run icon.
        b. Click on Authorize for the first popup - which authorizes Google Docs to execute the script on your behalf.
        c. Once you do that, the next step will require authorization for Gmail. You should click "Grant Access".
        d. Now this sets the script up, ready for actual execution.
        e. Go ahead and click run again.
        f. Another window should popup requesting authorization, Authorize it.
        g. A new popup should open Salesforce page where you have to Allow this application to connect to Salesforce.
        h. Once the window automatically closes and you are back to the script page, you should see that your attachment was saved to the "From Gmail" folder in Salesforce.
        i. After this step, subsequent executions of the script should not require any additional authorizations, unless you changed something in the source and saved it.

        Step 5: Set it up on a timer trigger
        To run the script automatically, set it up on a timer. Click Triggers and select Current Project's Triggers from the menu. Add a new row and select the Events as "Time-driven", "Minutes timer" and "Every 30 minutes" (or 10 or 5, depending on your need obviously). You can add a notification if the script failed for some reason.

        Save everything and that's it!

        You will notice that the script also creates a new label in Gmail called Salesforce and tags the processed emails with it. It also marks them as Read.

        Here is the full source code for the script, it should be really easy to follow along.
        // begin

        // get the consumer key and secret - this should be from the Remote Access setup in SF
        var consumerKey = ScriptProperties.getProperty("ConsumerKey");
        var consumerSecret = ScriptProperties.getProperty("ConsumerSecret");;

        // add the OAuth service
        var oAuthConfig = UrlFetchApp.addOAuthService("salesforce");
        oAuthConfig.setAccessTokenUrl("https://login.salesforce.com/_nc_external/system/security/oauth/AccessTokenHandler");
        oAuthConfig.setRequestTokenUrl("https://login.salesforce.com/_nc_external/system/security/oauth/RequestTokenHandler");
        oAuthConfig.setAuthorizationUrl("https://login.salesforce.com/setup/secur/RemoteAccessAuthorizationPage.apexp?oauth_consumer_key="+encodeURIComponent(consumerKey));
        oAuthConfig.setConsumerKey(consumerKey);
        oAuthConfig.setConsumerSecret(consumerSecret);

        // login to Salesforce to get a session id
        var sessionLoginUrl = "https://login.salesforce.com/services/OAuth/u/21.0";
        var options = { method : "POST", oAuthServiceName : "salesforce", oAuthUseToken : "always" };
        var result = UrlFetchApp.fetch(sessionLoginUrl, options);
        var txt = result.getContentText();
        var accessToken = txt.match(/<sessionId>([^<]+)/)[1];
        var serverUrl = txt.match(/<serverUrl>([^<]+)/)[1];
        var instanceUrl = serverUrl.match(/^https?:\/\/[^\/]+/)[0];

        function myFunction() {
            // setup the Gmail label name, creating it if it doesn't exist
            var FOLDER_FROM = "Salesforce";
            var label = GmailApp.getUserLabelByName(FOLDER_FROM);
            if (!label) {
                GmailApp.createLabel(FOLDER_FROM);
                label = GmailApp.getUserLabelByName(FOLDER_FROM);
            }

            // get the Salesforce folder name and id
            var FOLDER_TO = "From Gmail";
            var FOLDER_TO_ID = getFolderId(FOLDER_TO);

            // Fetch unread emails sent to +Salesforce
            var threads = GmailApp.search("is:unread to:+" + FOLDER_FROM);
            if (threads) {
                for (var i in threads) {
                    var messages = threads[i].getMessages();
                    for (var j in messages) {
                        if (messages[j].isUnread()) {
                            var attachments = messages[j].getAttachments();
                            for (var k in attachments) {
                                saveAttachment(FOLDER_TO_ID, attachments[k]);
                            }
                        }
                    }
                }
                label.addToThreads(threads);
                GmailApp.markThreadsRead(threads);
            }
        }

        function saveAttachment(folderId, blob) {
            var docName = blob.getName();
            var contentType = blob.getContentType();
            var encodedDoc = Utilities.base64Encode(blob.getBytes());

            var docUrl = instanceUrl + "/services/data/v20.0/sobjects/Document/";
            var queryStr = { "Name" : docName, "FolderId" : folderId, "ContentType" : contentType, "Body" : encodedDoc };

            // Salesforce REST API expects the methods to submit JSON requests - set contentType and payload accordingly
            response = UrlFetchApp.fetch(docUrl, {
                                    method : "POST",
                                    contentType : "application/json",
                                    headers : { "Authorization" : "OAuth "+accessToken },
                                    payload : Utilities.jsonStringify(queryStr) }
                              );
        }

        function getFolderId(folderName) {
            var soql = "SELECT Id,Name FROM Folder WHERE Name='" + folderName + "'";
            var queryUrl = instanceUrl + "/services/data/v21.0/query?q="+encodeURIComponent(soql);
            var response = UrlFetchApp.fetch(queryUrl, { method : "GET", headers : { "Authorization" : "OAuth "+accessToken } });
            var queryResult = Utilities.jsonParse(response.getContentText());
            var folderId = (queryResult && queryResult.records[0]) ? queryResult.records[0].Id : null;

            return folderId;
        }

        // end

        The timers are setup to execute in Google's cloud infrastructure, so you don't have to be logged in to either Gmail or Google Docs even though you create the Apps Script from Spreadsheet. Neat!

        The REST API developer documentation for Salesforce is available at: http://developer.force.com/REST

        Also, I should mention that I built upon the code from the blog posts Gmail Snooze with Apps Script and Connecting to Salesforce from Google Apps Script via OAuth and RESTful API.

        Wednesday, September 14, 2011

        Gmail Search Operators

        Recently I had to find a certain email message (which had an attachment) and after couple of quick scans I checked to see if Gmail had an option to search for messages with attachments. Sure enough, there was one: "from:xyz has:attachment". It shows all conversations with messages from xyz having an attachment.

        You can also search for a specific filename using "filename:abc.txt". One thing I noticed was if you are looking for an attachment named abc2.txt or 4abc.txt, then searching with "filename:abc" doesn't bring it up; you have to search for "filename:abc2" or "filename:4abc" - really??

        For the full range of search options in Gmail, check out their help page: https://mail.google.com/support/bin/answer.py?hl=en&answer=7190