10

I have created an email service based on the Salesforce documentation found at the following address:

https://help.salesforce.com/apex/HTViewHelpDoc?id=code_email_services_editing.htm

The only issue is that my class (which clearly impliments the InboundEmailHandler) is not being recognised as a compatible email service class.

My class:

global class processEnquiryEmail implements Messaging.InboundEmailHandler {
 global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) { 
   Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();

   Inbound_Email__c ie = new Inbound_Email__c(); 
   ie.From__c = email.fromname; 
   ie.Body__c = email.plainTextBody; 
   ie.Subject__c = email.subject; 
   ie.Email__c = envelope.fromAddress;

   try{insert ie;}
   catch(Exception e){
      system.debug('There was an error processing the email. ' + ie); }   
   return result; 
  }
}

and I am getting the following error when i try to activate my email service:

The Apex Class selected is not valid. An Apex Class that implements the Messaging.InboundEmailHandler interface must be selected.

Does anyone know why I can not use the above class in my email service? What is making it incompatible?

4 Answers 4

13

After speaking to Salesforce support I have resolved the issue. Rather than delete the post i will answer it incase anyone has similar issues...

The support consultant literally took a copy of my class, deleted it from the system and reinstated it again. After doing this the class became compatible with the Email Service despite no code changing.

I recommend following the above steps before racking your brains over it as I did. It is obviously just a Salesforce bug...

5
  • i have a vague genetic memory that if the class is not marked as active, it can't be selected. I seem to recall having to write a testmethod and executing it (probably could use anonymous apex too) to get the class to be acceptable
    – cropredy
    Commented Jan 28, 2015 at 1:56
  • 2
    I actually already had a test method, run with 90% coverage (stupid try-catches) and the apex class was definitely active. This has happened to me in the past but with scheduled apex classes, never with email services.. It is obviously a bug across the board that developers need to be aware of Commented Jan 28, 2015 at 2:14
  • my other vague genetic memory was that I had to create the class using the UI not Eclipse to get it to be accepted ...but this of course was not consistent
    – cropredy
    Commented Jan 28, 2015 at 2:22
  • 2
    I just ran into this. The class is invalid (needs recompilation). If you go to the Apex Class listing page and filter on Is Valid = false, you'll see it listed. 'Compile All' of the classes from that listing page and then the classes should go away in the Is Valid = true filtered list view. Then you can use the class in the Email Service setup. Commented Sep 15, 2016 at 18:51
  • Had the same problem. In my case, I just made a change to the class so that it pushed, then it worked :|.
    – mikeyq6
    Commented Jul 27, 2021 at 16:20
3

This error indicates that the packaged Apex Class has not yet been compiled. Typically, Apex Classes are compiled when saved. However, Apex Classes associated with Managed Packages cannot be saved so they rely on the runtime engine to compile them, either when they are first used or at some point automatically after they are installed.

If you encounter this error, please follow the steps below to manually compile that Apex Class:

  1. Navigate to Setup > Develop > Apex Classes.
  2. On the Top Left, click the link labeled “Compile all classes”.
  3. Once Compilation is complete, reattempt setting up the Email Service

Thanks I hope this will helps you.

Edit: the Known Issue writeup is here, and hopefully someone from Known Issues team will augment that writeup to include this workaround.

2

I faced the same issue with Email Services (with a bonus of Sandbox vs Production problem).

I created a class in the sandbox that implemented the Messaging.InboundEmailHandler interface which worked fine in the sandbox but I got the same error in production, after reading the solution support gave to David I tried something that shouldn't work but it did.

I fixed the error (or find a workaround for the bug) by compiling the class in production from the IDE (I'm using MavensMate) and then I was able to create the Email Service without any problem.

Note: Just in case you can't wait for support to get back to you.

-2
<p>

// Assign the case to 1 of the 20 Queues based on priority among multiple recepient 20 email ids in To & cc. Prevent Duplicate case.
// Solution: Email to case Replaced by 1 "Email Services" with "email address" (20 emails ids forwarded to this)
1 Custom metadatatype

public class CreateTaskEmailExample implements Messaging.InboundEmailHandler {
public class InboundEmailHandlerException extends Exception {}
public Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) {
Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
String errorMessage = '';
MailBox__mdt SingleMail = null;
Case case1 = null;
try {
SingleMail = checkpriority(email, envelope);
case1 = email.inreplyto == null ? insertCase(email, SingleMail) : updateCase(email);
createFilesByEmailAttachments(email.binaryAttachments, case1.Id);
createEmailRecord(case1, email, SingleMail);
result.success = true;
} catch (Exception error) {
result.success = false;
result.message = error?.getMessage() + ' ' + error?.getStackTraceString();
}
return result;
}
// Option#1: check email priority method and decide if the case needs to be created; prevent duplicate case
private MailBox__mdt checkpriority(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) {
// get the delivered to email id which fires Email services (Note: Mesage Id is unique)
String s = envelope.fromAddress;
String deliveredTo = s.substring(0, s.indexOf('+')) + s.substring(s.indexOf('@'));
// get list of To & CcAddress
List<String> recipientAddresses = new List<String>();
recipientAddresses.addAll(email.toAddresses);
if(email.ccAddresses != null) {recipientAddresses.addAll(email.ccAddresses);}
// get the priority email for which case needs to be created
List<MailBox__mdt> SingleMailList = [SELECT Id, Queue_Id__c, Priority__c, ReceiverEmail__c, Email_template__c, Email2__c
FROM MailBox__mdt
WHERE Email2__c IN:recipientAddresses
ORDER BY Priority__c LIMIT 1];
MailBox__mdt SingleMail = SingleMailList[0];
// Prevent Further Execution for lower priority triggering email id
if (deliveredTo != SingleMail.Email2__c) {
throw new InboundEmailHandlerException('deliveredToValue is not equal to Priority i.e. SingleMail.Email2__c');
}
System.debug('Proceed');
return SingleMail;
}

// Create case for First Incoming Email
private Case insertCase(Messaging.InboundEmail email, MailBox__mdt SingleMail) {
Case case1 = new Case(
Subject = email.subject,
Description = email.plainTextBody,
Origin = 'Email',
Status = 'New',
Priority = 'Low',
OwnerId = SingleMail.Queue_Id__c,
Message_Id__c = email.messageId, // Option #2: make this unique field and prevent duplicate case at the cost of extra DMLs.
SuppliedEmail = email.fromAddress,
SuppliedName = email.fromName,
RecordTypeId = SingleMail.Case_RecordTypeId__c,
Type = 'Enquiry'
);
// link Account and contact
List<Account> account = [Select id, PhoneNo., Email from Account where Email =:email.replyTo];
if(account.size() == 1) {
case1.AccountId = account[0].id;
List<Contact> contact = [Select id from Contact where AccountId =: account[0].id];
if(contact.size() == 1) {case1.ContactId = contact[0].id;}
}
Insert case1;
return case1;
}

// Update case for Replied Incoming Email (Third)
private Case updateCase(Messaging.InboundEmail email) {
// get threadIdentifier/messageIdentifier that can relate to the already existing Case
List<EmailMessage> emailMessage1 = [SELECT RelatedToId FROM EmailMessage
WHERE MessageIdentifier = :email.inReplyTo LIMIT 1];
// get related already existing Case
List<Case> caseList = [SELECT Id, Message_Id__c, Subject, Description, OwnerId, CaseNumber FROM Case
WHERE Id =: emailMessage1[0].RelatedToId LIMIT 1];
Case case1 = caseList[0];
case1.Message_Id__c = email.messageId;
case1.Description += email.plainTextBody; // character limit 32000, truncate may be required
Update case1;
return case1;
}

// Create attachments, check the Checkbox "Convert to binary" on "Email Service" definition
private void createFilesByEmailAttachments(List<Messaging.inboundEmail.BinaryAttachment> inboundAttachments, Id caseId) {
if (inboundAttachments == null) {return;}
List<Attachment> lstAttachment = new List<Attachment>();
for (Messaging.inboundEmail.BinaryAttachment currentAttachment : inboundAttachments) {
Attachment attachment = new Attachment();
attachment.ParentId = caseId;
attachment.Name = currentAttachment.filename;
attachment.Body = currentAttachment.body;
lstAttachment.add(attachment);
}
Insert lstAttachment;
}

// Create Email and relate it to case if it's a reply
private void createEmailRecord(Case case1, Messaging.InboundEmail email, MailBox__mdt SingleMail) {
EmailMessage emailMessage = new EmailMessage(
HtmlBody = 'To: ' + String.join(email.toAddresses, ', '), // add to, cc for reference
Headers = String.valueOf(email.headers),
Subject = email.subject,
FromName = email.fromName,
FromAddress = email.fromAddress,
ToAddress = SingleMail.Email2__c, // custom MDT emailid @priority
Incoming = true,
Status = '0',
IsClientManaged = true,
MessageDate = DateTime.now() // header has date
);
if(case1.Id != null) {emailMessage.RelatedToId = case1.Id;}
if (email.ccAddresses != null) {emailMessage.HtmlBody += '
' + 'cc: ' + String.join(email.ccAddresses, ', ');}
emailMessage.HtmlBody += '
' + email.htmlBody; // increase char limit 32000 to 1 lakh
// if email is a reply, get threadIdentifier/messageIdentifier & add the same thread to email
if (email.inReplyTo != null) {
List<EmailMessage> emailMessage2 = [SELECT RelatedToId FROM EmailMessage
WHERE MessageIdentifier = :email.inReplyTo LIMIT 1];
emailMessage.MessageIdentifier = email.inReplyTo;
emailMessage.ThreadIdentifier = email.inReplyTo;
emailMessage.ReplyToEmailMessageId = emailMessage2[0].ReplyToEmailMessageId;
}
Insert emailMessage;
}
}

2
  • The original poster already answered their own question. How does your answer differ from their own accepted answer? Commented Nov 10 at 19:27
  • This doesn't seem to answer the question of "why wasn't the email service able to be activated?". Also, again, the explanation is as important as the solution itself.
    – Derek F
    Commented Nov 11 at 16:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .