Интеграция со сторонним сервисом с помощью Email

image
Столкнулись с ситуацией, когда существует сервис, который уже никак не может быть изменён, но и через REST или SOAP с ним взаимодействовать тоже не получится. Но нашёлся 1 способ.

Так как сервис может принимать и отправлять Email, то с его помощью и было решено наладить с ним связь.

Идея заключалась в том, что к нам в Salesforce приходит Email, и из него уже будет взят Attachment или текст из body имэйла.
Далее делаем парсинг пришедших данных, и, если надо, отправляем email в ответ.

EmailServiceHandler
global class UploadInvoicesEmailServiceHandler implements Messaging.InboundEmailHandler {
    private static final String endOfLine = '\n';

    global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, 
        Messaging.InboundEnvelope envelope) {
        Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
        try {
            List<InvoiceDTO> invoiceDTOs = new List<InvoiceDTO>();
            if (email.textAttachments != null && !email.textAttachments.isEmpty()) {
                for (Messaging.InboundEmail.TextAttachment  textAttachment : email.textAttachments) {
                    if (textAttachment.mimeTypeSubType == 'text/csv' ||
                        textAttachment.mimeTypeSubType == 'multipart/mixed') {
                        String content = textAttachment.body;
                        String fileName = textAttachment.fileName;
                        List<String> contentLines = content.split(endOfLine);
                        if (isValidAttachment(fileName, contentLines)) {
                            List<UserIdDTO> parsedInvoiceDTOs = getParsedInvoiceIds(contentLines);
                            invoiceDTOs.addAll(parsedInvoiceDTOs);
                        }
                    }
                }
            }
            /* Use the next if you need to work with binary attachments
            if (email.binaryAttachments != null && !email.binaryAttachments.isEmpty()) {
                for (Messaging.InboundEmail.BinaryAttachment binAttachment : email.binaryAttachments) {
                    //Do some work
                }
            }
            */
            if (!invoiceDTOs.isEmpty()) {
                List<Invoice__c> invoicesToUpsert = getInvoicesToUpsert(invoiceDTOs);
                upsert invoicesToUpsert;

                result.success = true;
                result.message = 'Upload was performed successfully.';
            }
        } catch (Exception ex) {
            result.success = false;
            result.message = 'Upload failed: ' + ex.getMessage();
        }
        
        return result;
    }

    private Boolean isValidAttachment(String fileName, List<String> contentLines) {
        // Some content validation logic
    }

    private List<InvoiceDTO> getParsedInvoiceIds(List<String> contentLines) {
       // Some parsing logic
        return invoiceDTOs;
    }

   
    private List<Invoice__c> getInvoicesToUpsert(List<UserIdDTO> invoiceDTOs) {
        // Some logic for converting DTOs to sObjects
        return invoicesToUpsert;
    }

    
    private class InvoiceDTO {
        public String invoiceName { get; set; }
        public DateTime invoiceDate { get; set; }
        public Decimal amount { get; set; }
        /*
        Add the new fields here for whatever you need
        */

        public InvoiceDTO(String invoiceName,
                         String invoiceDate,
                         String amount) {
            this.invoiceName = invoiceName;
            this.invoiceDate = invoiceDate;
            this.amount = amount;
        }
    }
}

Выше представлен итоговый результат. Давайте детальнее рассмотрим такой подход.

Все данные, полученные из email, будут храниться в обёртке над объектом Invoice__c.

 private class InvoiceDTO {
        public String invoiceName { get; set; }
        public DateTime invoiceDate { get; set; }
        public Decimal amount { get; set; }
        /*
        Add the new fields here for whatever you need
        */
        public InvoiceDTO(String invoiceName,
                         String invoiceDate,
                         String amount) {
            this.invoiceName = invoiceName;
            this.invoiceDate = invoiceDate;
            this.amount = amount;
        }
    }

Собственно сам парсинг заключается в получении определённых данных из пришедшего Email, с помощью Messaging.InboundEmail type.

global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) {
        Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
        try {
            List<InvoiceDTO> invoiceDTOs = new List<InvoiceDTO>();
            if (email.textAttachments != null && !email.textAttachments.isEmpty()) {
                for (Messaging.InboundEmail.TextAttachment  textAttachment : email.textAttachments) {
                    if (textAttachment.mimeTypeSubType == 'text/csv' ||
                        textAttachment.mimeTypeSubType == 'multipart/mixed') {
                        String content = textAttachment.body;
                        String fileName = textAttachment.fileName;
                        List<String> contentLines = content.split(endOfLine);
                        if (isValidAttachment(fileName, contentLines)) {
                            List<UserIdDTO> parsedInvoiceDTOs = getParsedInvoiceIds(contentLines);
                            invoiceDTOs.addAll(parsedInvoiceDTOs);
                        }
                    }
                }
            }
            /* Use the next if you need to work with binary attachments
            if (email.binaryAttachments != null && !email.binaryAttachments.isEmpty()) {
                for (Messaging.InboundEmail.BinaryAttachment binAttachment : email.binaryAttachments) {
                    //Do some work
                }
            }
            */
            if (!invoiceDTOs.isEmpty()) {
                List<Invoice__c> invoicesToUpsert = getInvoicesToUpsert(invoiceDTOs);
                upsert invoicesToUpsert;

                result.success = true;
                result.message = 'Upload was performed successfully.';
            }
        } catch (Exception ex) {
            result.success = false;
            result.message = 'Upload failed: ' + ex.getMessage();
        }
        
        return result;
    }

Весь доступный функционал для работы с Email в Apex вы можете найти по ссылкам: