I have a process that I am looking to create where people can send an email to a specific email address to update the Stage and a custom field called Update. I would like this to be pulled from the body but since I am updating two fields I am not sure exactly how to accomplish this. The email that would be sent would look something like this:

Stage: Closed Won

Update: I am an Update

Whatever is after the colon should be placed in the appropriate field.

Below is what I have so far:

global class OpportunityUpdateEmailHandler implements Messaging.InboundEmailHandler {
    global Messaging.InboundEmailResult handleInboundEmail(
    Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) {
      String subject = email.subject;
      Pattern idPattern = Pattern.compile('006[A-Za-z0-9]{12}');
      Matcher matcher = idPattern.matcher(subject);
      if (!matcher.find()) System.assert(false, 'No Opportunity ID found in the Subject!');
        Opportunity opp = [SELECT Name, StageName FROM Opportunity WHERE Id = :matcher.group(0)];
        opp.StageName = email.plainTextBody;       
        update opp;
      Messaging.InboundEmailresult result = new Messaging.InboundEmailResult();
      result.message = 'You have successfully updated this Opportunities stage to ' + opp.StageName;
      return result;
  • How would you replace that? – cmmoutes13 Nov 23 '16 at 20:19
  • And my question is how can I use the body to update two fields instead of one. If that makes sense lol. Like now I am just placing the value in the body into the stage field. I would like to use the body to update both stage and update. – cmmoutes13 Nov 23 '16 at 20:21

Never use system.assert(false) to validate your production code, ever. It is meant for use in tests only, and the exceptions thrown by this approach are not catchable. If you wish to throw an exception, throw an exception.

public class MyCustomException extends Exception { }

if (someErrorCondition) throw new MyCustomException('<exception_message>');

You could write a parser in whatever manner you wish. Likely, you will want to map each field by its label, so you can specify My Field: Some Value instead of My_Field__c: Some Value. If you want to support just strings, the following will get you started. If you want to support all field types, it gets much more complicated.

Map<String, SObjectField> labelToField = new Map<String, SObjectField>();
for (SObjectField field : SObjectType.Opportunity.fields.getMap().values())
    labelToField.put(field.getDescribe().getLabel().toLowerCase(), field);
Matcher m = Pattern.compile('(?m)^([\\w\\s]*):(.*)$').matcher(body);
while (m.find())
    String fieldLabel = m.group(1);
    String fieldValue = m.group(2);
    if (fieldLabel == null || fieldValue == null) continue;

    SObjectField field = labelToField.get(m.group(1).trim().toLowerCase());
    if (field == null) return;

    queriedOpportunity.put(field, fieldValue.trim());

Expression explained:

  • (?m) - Multiline flag, which makes ^ and $ match the start/end of a line
    • Opposite of (?s) - Single line flag, which makes dot match newline characters
  • ^ - Match the start of the line
  • ([\\w\\s]*): - Match all word characters or whitespace characters until a colon is found
  • :(.*) - Match all characters except newline characters after the colon is found
  • $ - Match the end of the line
  • I am not quite understanding this. All I want to do is take whatever is in the body after "Stage:" and update the StageName and then whatever is after Update: will go in the Update__c field – cmmoutes13 Nov 23 '16 at 21:02
  • And this code would accomplish that. It takes whatever is before the colon and finds the field with a matching label. Then it takes whatever is after the colon and puts that value in the field. – Adrian Larson Nov 23 '16 at 21:11
  • My concern is that isn't the update technically after the first colon? So would that get put in the stage? – cmmoutes13 Nov 23 '16 at 21:14
  • It's on a line by line basis. With the m flag set (the (?m) portion at the start), the ^ character matches the start of the line, and the $ character matches the end of a line. And the . character does not match newline characters. – Adrian Larson Nov 23 '16 at 21:17
  • @cmmoutes13 Does that make more sense after adding a detailed explanation of the expression? – Adrian Larson Nov 23 '16 at 22:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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