Apex APIs
The Apex surface is a global, versioned API in the rme namespace.
Builder API
RME_Message.Result result = RME_Message.builder()
.channel('EMAIL')
.templateName('Order_Confirmation')
.templateLanguage('en_US')
.toContact(contactId)
.recordId(orderId)
.category('Transactional')
.fromDomain('example.com')
.replyTo('support@example.com')
.parameter('promoCode', 'WELCOME10')
.attachment(contentVersionId)
.schedule('LOCAL', '09:00')
.priority('HIGH')
.send();
Result
public class Result {
public Id messageId; // Message__c record id
public String status; // SENT | QUEUED | SCHEDULED | SUPPRESSED | FAILED
public String resolvedChannel;
public String provider;
public String providerMessageId;
public String errorCode;
public String errorMessage;
}
Bulk send
List<RME_OutboundMessage> messages = new List<RME_OutboundMessage>();
for (Contact c : [SELECT Id FROM Contact WHERE Renewal_Due__c = TRUE LIMIT 5000]) {
messages.add(RME_Message.builder()
.channel('EMAIL')
.templateName('Renewal_Notice')
.toContact(c.Id)
.build());
}
List<RME_Message.Result> results = RME_Message.sendAll(messages); // synchronous, chunked
// or
System.enqueueJob(new RME_BulkSendQueueable(messages, 200)); // asynchronous
Invocable Apex
global with sharing class RME_SendMessageAction {
global class Request {
@InvocableVariable(required=true) global String channel;
@InvocableVariable global String templateName;
@InvocableVariable global Id contactId;
@InvocableVariable global Id contextRecordId;
@InvocableVariable global String category;
}
global class Response {
@InvocableVariable global Id messageId;
@InvocableVariable global String status;
@InvocableVariable global String errorMessage;
}
@InvocableMethod(label='Send Message (RME)' category='Real Messaging Engine')
global static List<Response> send(List<Request> requests) { /* ... */ return null; }
}
Services
| Class | Purpose |
|---|---|
RME_Message | Build and send |
RME_Scheduler | Schedule, cancel, reschedule |
RME_Consent | Read and write consent per channel and category |
RME_Suppression | Add, remove, and test suppression |
RME_TemplateRenderer | Render and preview templates |
RME_DeliveryStatus | Query normalized delivery state |
RME_Diagnostics | Configuration and health checks |
Governor limits
RME issues one callout per provider request. Callouts cannot run in the same transaction as prior DML in a trigger context — use sendAsync() or a Queueable:
trigger OrderTrigger on Order (after update) {
System.enqueueJob(new OrderConfirmationQueueable(Trigger.newMap.keySet()));
}
| Limit | Guidance |
|---|---|
| 100 callouts / transaction | Chunk bulk sends; default chunk 200 messages per Queueable |
| 10 s callout timeout | RME sets 20 s where allowed and retries on timeout |
| 50 Queueable chains | RME_BulkSendQueueable self-chains within the limit |
| No callout after DML | Use async entry points from triggers |
Testing
@IsTest
private class OrderConfirmationTest {
@IsTest static void sendsConfirmation() {
RME_Test.mockProvider('SENDGRID', 202, '{"id":"test-123"}');
Test.startTest();
RME_Message.Result r = RME_Message.builder()
.channel('EMAIL').toAddress('qa@example.com')
.subject('Test').body('Body').send();
Test.stopTest();
System.assertEquals('SENT', r.status);
System.assertEquals(1, [SELECT COUNT() FROM rme__Message__c]);
}
}
RME_Test.mockProvider installs an HttpCalloutMock for the named provider so tests never require real credentials.
Continue to Platform Events.
Was this helpful?
Last updated 1 month ago