Народ, помогите.
Стоит задача послать письмо с вложенным файлом в SendGrid
В документации написано что надо отправлять через POST в формате multipartform-data
Начал гуглить и не могу понять - все примеры почему-то составляют тело запроса вручную. Всю эту кашу метаданных запроса реально хардкодят.
Вот как тут например - http://blog.enree.co/2013/01/salesforce-apex-post-mutipartform-data.html
Кто сталкивался - это реально так? Если у вас есть рабочий пример как отправить файл в SendGrid буду очень признателен.
Потому что наши нашли и внедрили вот это
https://github.com/sendgrid/sendgrid-apex
Но по ходу эта библиотека с файлами не очень хорошо работает - сразу отвалилась с ошибкой
BLOB is not a valid UTF-8 string
а любые попытки исправить приводят к тому что файл вроде и приходит но битый (т.е. не понятно что там внутри приходит)
Собственно вот как формируется тело запроса в отношении файлов в этой либе
if (!this.files.isEmpty()) {
for (String filename : this.files.keySet()){
Blob value = this.files.get(filename);
String encoded = EncodingUtil.urlEncode(value);
output += '&files['+filename+']=' + encoded;
}
}String encoded = EncodingUtil.base64Encode(value)
попробуй так.
Честно не особо понял проблему,я просто вспомнил у меня была проблема из респонса возвращался файл так вот любые попытки сделать Blob.VAlueOf() обламывались,потом оказалось что у объекта респонс есть собственный метод для этого.
так письмо или запрос ?
Запрос. Письмо уже формируется на стороне SendGrid.
попробуй так.
Вроде пробовал уже так - не прокатило.
Сейчас еще раз попробую, скажу что конкретно не прокатило.
Вот да, проблема в том что если так делать, то вложения приходят но они битые - внутри хрень полная вместо тела файла.
У меня вывих мозга
Воспроизвожу отправку запроса с файлом в Postman
Вот в таком виде отлично все работает


Но любые попытки вставить тело файла в текстовом виде (кодированный в base64) не проходят.
Видно что все что передается как тело файла прямо в файл и попадает.
Теперь собственно вопрос - как можно воспроизвести такой запрос как Postman из SF - я так понимаю что тело файла передается в Binary(Blob) виде.
SF - не передает бинарные данные ни в каком виде. он передает их как base64. Может в этом и проблема.
Да вот пока сложно понять в чем проблема.
Продолжаю разбираться. Честно первый раз сталкиваюсь с отправкой файла в POST запросе.
И не могу понять как понять как передается само тело файла по тому что я вижу в Postman.
По ходу надо брать Proxy и смотреть через него а потом воспроизводить это в SF посимвольно.
Текстовые файлы нормально передаются ? Начни сначала с них.
Да! Передаются нормально!
На счет передачи только в base64
Вот столкнулся с таким
setBodyAsBlob для http request в SF
Так что не все по ходу, а можно и в чистом виде запулить тело запроса.
Вот думаю пока как с этим подружиться
Насколько я понял у тебя есть Attachment из него надо получить стринг, String bodyContent = myAttachment.body.toString(). Почти уверен что так все за работает.
либо так String data = EncodingUtil.base64Decode(myEncodedString).toString();
Зря ты в этом уверен
BLOB is not a valid UTF-8 string
И так вернет стринг, зачем делать еще раз .toString?
Сейчас, вчитаюсь!
Не
Тут в примере Blob получают из строки в UTF-8. С этим нет проблем.
Но в случае файлов - Blob состоит из бинарных данных и получить из него строку нельзя
будет вот это BLOB is not a valid UTF-8 string
Остается EncodingUtil.base64Decode(blob), но с этим не работает
И главное не могу понять почему! Вроде читал что нормально когда кодируется тело файла в base64 и передается и принимающая сторона должна декодировать обратно. Но вот что-то не получается. Пробовал даже специальные хедеры.
Мне кажется решение очень простое - просто я что-то упускаю!
Так и не получилось что-то найти решение. Пока дали отмашку остановиться и переключиться на другую задачу.
Ну по ходу мы не одни во вселенной
https://developer.salesforce.com/forums/?id=906F00000008wBnIAI
Вот еще раз приложу эту ссылку - по ходу это единственный толковая информаци по данной проблеме
http://blog.enree.co/2013/01/salesforce-apex-post-mutipartform-data.html
Буду разбираться уже в свободное время.
ДА!!!!! Я сделал это!!!!
Вот этот пример работает!
http://blog.enree.co/2013/01/salesforce-apex-post-mutipartform-data.html
я конечно не понял половину того что там происходит несмотря на описание почти каждой строчки
Но получилось даже усовершенствовать код. Сделал поддержку отправки запроса с несколькими файлами.
Теперь SendGrid можно использовать на полную
После того как поработал с кодом скажу так - решение явно выпадает за рамки обычных и товарищу которые это придумал огромный респект. Я бы никогда не додумался копать настолько глубоко!!!
ха, только вчера читал эту статью пока рыскал в поиске решений по парсингу мультипарт реквестов на стороне форса.
Единственное что отметил, это валидный комментарий к статье, что в случае оканчивания файла на не-UTF символ, оно закономерно упадет. Все равно лучше чем ничего, хотя такое лучше решать внешним пуллером за пределами форса.
Что ты имеешь в виду под "внешним пуллером"?
Реальный пример можешь привести?
Hi Dmirty Shnyrev, I have been trying to send an email with pdf attachment from Salesforce using SendGrid. But I was not successful. I saw your comment in one of the blog that you have sendgrid functionality working with pdf attachments. Would you please share me the code to send a single pdf file from salesforce via sendgrid? I tried below the code but it is not working.. my email id: mcsreddy86@gmail.com
I have below the code. Is the request construction correct? It is not working and it says bad request.
String body;
String boundary = '__boundary__xxx';
String filename = 'app.pdf';
String header = '--'+boundary+'n';body += 'Content-Disposition: form-data; name="data"; filename="'+filename+'"nContent-Type: application/octet-stream';
body += 'Content-Disposition: form-data; name="api_user"'+'\r\n\r\n'+'superuser'+'\r\n\r\n' ;
body += 'Content-Disposition: form-data; name="api_key"'+'\r\n\r\n'+'superuser123'+'\r\n\r\n' ;
body += 'Content-Disposition: form-data; name="to"'+'\r\n\r\n'+'someemail@gmail.com'+'\r\n\r\n';
body += 'Content-Disposition: form-data; name="from"'+'\r\n\r\n'+'otheremail@gmail.com'+'\r\n\r\n';body += 'Content-Disposition: form-data; name="text"'+'\r\n\r\n'+'sometexttttttttttt'+'\r\n\r\n' ;
String footer = 'n--'+boundary+'--';
// no trailing padding on header by adding ' ' before the last "nn" charactersString headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'nn'));
//this ensures no trailing "=" padding
while(headerEncoded.endsWith('=')){
header+=' ';
headerEncoded = EncodingUtil.base64Encode(Blob.valueOf(header+'nn'));
}
//base64 encoded body
Blob blobFile = CustomClass.GetFileAsBlob('http://www.tutorialspoint.com/java/pdf/java_strings.pdf', 'pdf', 'URL');
String bodyEncoded = EncodingUtil.base64Encode(blobFile);//base64 encoded footer
String footerEncoded = EncodingUtil.base64Encode(Blob.valueOf(footer));
Blob bodyBlob = null;//last encoded body bytes
String last4Bytes = bodyEncoded.substring(bodyEncoded.length()-4,bodyEncoded.length());
//if the last 4 bytes encoded base64 ends with the padding character (= or ==) then re-encode those bytes with the footer
//to ensure the padding is added only at the end of the body
if(last4Bytes.endsWith('='))
{
Blob decoded4Bytes = EncodingUtil.base64Decode(last4Bytes);
HttpRequest tmp = new HttpRequest();
tmp.setBodyAsBlob(decoded4Bytes);
String last4BytesFooter = tmp.getBody()+footer;
bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded.substring
(0,bodyEncoded.length()-4)+EncodingUtil.base64Encode(Blob.valueOf(last4BytesFooter)));
}else
{
bodyBlob = EncodingUtil.base64Decode(headerEncoded+bodyEncoded+footerEncoded);
}HttpRequest req = new HttpRequest();
req.setHeader('Content-Type','multipart/form-data; boundary='+boundary);
req.setMethod('POST');
req.setEndpoint('https://sendgrid.com/api/mail.send.xml');
req.setBodyAsBlob(bodyBlob);
req.setTimeout(60000);
req.setHeader('Content-Length',String.valueof(req.getBodyAsBlob().size()));
Http http = new Http();
HTTPResponse res = http.send(req);
System.debug('ressssssssss:'+res);
Дима, твоя популярность растет)
Hi.
Sorry, I can't share my result code because of NDA, but here is my advice.
First of all, I see you use old example from the article.
Please use last one in UPDATE section. I tested it and I like it more.
This method allows you send file itself, but SendGrid requires some other information too.
Add this section before file data.
...
String header = '';
header += '--'+boundary+'\r\n';
header += 'Content-Disposition: form-data; name="api_user"\r\n\r\nXXXXXXXXXX\r\n';
header += '--'+boundary+'\r\n';
header += 'Content-Disposition: form-data; name="api_key"\r\n\r\nZZZZZZZZZZZZ\r\n';
header += '--'+boundary+'\r\n';
header += 'Content-Disposition: form-data; name="to"\r\n\r\nsuper@gmail.com\r\n';
header += '--'+boundary+'\r\n';
header += 'Content-Disposition: form-data; name="from"\r\n\r\nno-reply@gmail.com\r\n';
header += '--'+boundary+'\r\n';
header += 'Content-Disposition: form-data; name="fromname"\r\n\r\nSuperCompany\r\n';
header += '--'+boundary+'\r\n';
header += 'Content-Disposition: form-data; name="subject"\r\n\r\ntest 3\r\n';
header += '--'+boundary+'\r\n';
header += 'Content-Disposition: form-data; name="text"\r\n\r\n1111111111\r\n';
header += '--'+boundary+'\r\n';
header += 'Content-Disposition: form-data; name="html"\r\n\r\n1111111111\r\n';
...
<file data section here>
...
So with last example from the article and this additional data you should receive right request for SendGrid.
Сам поражаюсь ![]()
Ты бы ответил товарищу!))
Ну так ответил
Кстати хорошая новость
- спросил разрешения выложить рабочий пример у директора на github!
Получил добро
Скоро ссылку скину.
Этот товарищ кстати уже не первый кто спрашивает! Просто он по ходу самый настырный. Даже сюда умудрился написать. Я это сообщения разве что в Вконтакте не видел ![]()
Hi Dmirty Shnyrev,
I was able to send an email with pdf attachment. Thank you very much for your help here.
I have a question, how can I send multiple files to the same email address?
Do I need include multiple headers as below?
header += '--'+boundary+'\r\nContent-Disposition: form-data; name="files[receipt.pdf]";\nContent-Type: application/pdf';
Please help me !
Thanks!
I shared full example under my company Github account!
https://github.com/Kaptio/SalesforceToSendgridWithAttachmentsExample
Please enjoy it ![]()
Hi Dmitry Shnyrev,
Thank you so much for your help. It is working now. :-)