Народ, помогите.
Стоит задача послать письмо с вложенным файлом в 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
а любые попытки исправить приводят к тому что файл вроде и приходит но битый (т.е. не понятно что там внутри приходит)
Народ, помогите. Стоит задача послать письмо с вложенным файлом в 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;
}
}
Собственно вот как формируется тело запроса в отношении файлов в этой либе [code]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; } }[/code] Мне не сильно нравится как вставляется тело файла в запрос
String encoded = EncodingUtil.base64Encode(value)
попробуй так.
[quote="Dmitry Shnyrev"]String encoded = EncodingUtil.urlEncode(value);[/quote] String encoded = EncodingUtil.base64Encode(value) попробуй так.
Честно не особо понял проблему,я просто вспомнил у меня была проблема из респонса возвращался файл так вот любые попытки сделать Blob.VAlueOf() обламывались,потом оказалось что у объекта респонс есть собственный метод для этого.
Честно не особо понял проблему,я просто вспомнил у меня была проблема из респонса возвращался файл так вот любые попытки сделать Blob.VAlueOf() обламывались,потом оказалось что у объекта респонс есть собственный метод для этого.
так письмо или запрос ?
[quote="Dmitry Shnyrev"]Стоит задача послать письмо с вложенным файлом в SendGrid[/quote][quote="Dmitry Shnyrev"]Стоит задача послать письмо с вложенным файлом в SendGrid[/quote] так письмо или запрос ?
Запрос. Письмо уже формируется на стороне SendGrid.
Запрос. Письмо уже формируется на стороне SendGrid.
попробуй так.
Вроде пробовал уже так - не прокатило.
Сейчас еще раз попробую, скажу что конкретно не прокатило.
[quote="wilder"]String encoded = EncodingUtil.base64Encode(value) попробуй так.[/quote] Вроде пробовал уже так - не прокатило. Сейчас еще раз попробую, скажу что конкретно не прокатило.
Вот да, проблема в том что если так делать, то вложения приходят но они битые - внутри хрень полная вместо тела файла.
[quote="Dmitry Shnyrev"]Сейчас еще раз попробую, скажу что конкретно не прокатило.[/quote] Вот да, проблема в том что если так делать, то вложения приходят но они битые - внутри хрень полная вместо тела файла.
У меня вывих мозга
Воспроизвожу отправку запроса с файлом в Postman
Вот в таком виде отлично все работает
Но любые попытки вставить тело файла в текстовом виде (кодированный в base64) не проходят.
Видно что все что передается как тело файла прямо в файл и попадает.
Теперь собственно вопрос - как можно воспроизвести такой запрос как Postman из SF - я так понимаю что тело файла передается в Binary(Blob) виде.
У меня вывих мозга Воспроизвожу отправку запроса с файлом в Postman Вот в таком виде отлично все работает [img]/pics/92/original_2016-01-19_13-12-24.png[/img] [img]/pics/91/medium_2016-01-19_13-13-36.png[/img] Но любые попытки вставить тело файла в текстовом виде (кодированный в base64) не проходят. Видно что все что передается как тело файла прямо в файл и попадает. Теперь собственно вопрос - как можно воспроизвести такой запрос как Postman из SF - я так понимаю что тело файла передается в Binary(Blob) виде.
SF - не передает бинарные данные ни в каком виде. он передает их как base64. Может в этом и проблема.
SF - не передает бинарные данные ни в каком виде. он передает их как base64. Может в этом и проблема.
Да вот пока сложно понять в чем проблема.
Продолжаю разбираться. Честно первый раз сталкиваюсь с отправкой файла в POST запросе.
И не могу понять как понять как передается само тело файла по тому что я вижу в Postman.
По ходу надо брать Proxy и смотреть через него а потом воспроизводить это в SF посимвольно.
Да вот пока сложно понять в чем проблема. Продолжаю разбираться. Честно первый раз сталкиваюсь с отправкой файла в POST запросе. И не могу понять как понять как передается само тело файла по тому что я вижу в Postman. По ходу надо брать Proxy и смотреть через него а потом воспроизводить это в SF посимвольно.
Текстовые файлы нормально передаются ? Начни сначала с них.
[quote="Dmitry Shnyrev"]Да вот пока сложно понять в чем проблема. Продолжаю разбираться. Честно первый раз сталкиваюсь с отправкой файла в POST запросе. И не могу понять как понять как передается само тело файла по тому что я вижу в Postman. По ходу надо брать Proxy и смотреть через него а потом воспроизводить это в SF посимвольно.[/quote] Текстовые файлы нормально передаются ? Начни сначала с них.
Да! Передаются нормально!
Да! Передаются нормально!
На счет передачи только в base64
Вот столкнулся с таким
setBodyAsBlob для http request в SF
Так что не все по ходу, а можно и в чистом виде запулить тело запроса.
Вот думаю пока как с этим подружиться
На счет передачи только в base64 Вот столкнулся с таким setBodyAsBlob для http request в SF Так что не все по ходу, а можно и в чистом виде запулить тело запроса. Вот думаю пока как с этим подружиться
Насколько я понял у тебя есть Attachment из него надо получить стринг, String bodyContent = myAttachment.body.toString(). Почти уверен что так все за работает.
Насколько я понял у тебя есть Attachment из него надо получить стринг, String bodyContent = myAttachment.body.toString(). Почти уверен что так все за работает.
либо так String data = EncodingUtil.base64Decode(myEncodedString).toString();
либо так String data = EncodingUtil.base64Decode(myEncodedString).toString();
Зря ты в этом уверен
BLOB is not a valid UTF-8 string
Зря ты в этом уверен BLOB is not a valid UTF-8 string
И так вернет стринг, зачем делать еще раз .toString?
[quote="Sergey Prichepo"]EncodingUtil.base64Decode(myEncodedString)[/quote] И так вернет стринг, зачем делать еще раз .toString?
[quote="Dmitry Shnyrev"][quote="Sergey Prichepo"]EncodingUtil.base64Decode(myEncodedString)[/quote] И так вернет стринг, зачем делать еще раз .toString?[/quote] [url=https://help.salesforce.com/apex/HTViewSolution?urlname=How-do-you-convert-a-Blob-to-string-1327108626373&language=en_US]Может это поможет[/url]
Сейчас, вчитаюсь!
Сейчас, вчитаюсь!
Не
Тут в примере Blob получают из строки в UTF-8. С этим нет проблем.
Но в случае файлов - Blob состоит из бинарных данных и получить из него строку нельзя
будет вот это BLOB is not a valid UTF-8 string
Остается EncodingUtil.base64Decode(blob), но с этим не работает
И главное не могу понять почему! Вроде читал что нормально когда кодируется тело файла в base64 и передается и принимающая сторона должна декодировать обратно. Но вот что-то не получается. Пробовал даже специальные хедеры.
Мне кажется решение очень простое - просто я что-то упускаю!
Не :( Тут в примере 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
Буду разбираться уже в свободное время.
Так и не получилось что-то найти решение. Пока дали отмашку остановиться и переключиться на другую задачу. Ну по ходу мы не одни во вселенной 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 можно использовать на полную
После того как поработал с кодом скажу так - решение явно выпадает за рамки обычных и товарищу которые это придумал огромный респект. Я бы никогда не додумался копать настолько глубоко!!!
ДА!!!!! Я сделал это!!!! Вот этот пример работает! http://blog.enree.co/2013/01/salesforce-apex-post-mutipartform-data.html я конечно не понял половину того что там происходит несмотря на описание почти каждой строчки :) Но получилось даже усовершенствовать код. Сделал поддержку отправки запроса с несколькими файлами. Теперь SendGrid можно использовать на полную :D После того как поработал с кодом скажу так - решение явно выпадает за рамки обычных и товарищу которые это придумал огромный респект. Я бы никогда не додумался копать настолько глубоко!!!
ха, только вчера читал эту статью пока рыскал в поиске решений по парсингу мультипарт реквестов на стороне форса.
Единственное что отметил, это валидный комментарий к статье, что в случае оканчивания файла на не-UTF символ, оно закономерно упадет. Все равно лучше чем ничего, хотя такое лучше решать внешним пуллером за пределами форса.
ха, только вчера читал эту статью пока рыскал в поиске решений по парсингу мультипарт реквестов на стороне форса. Единственное что отметил, это валидный комментарий к статье, что в случае оканчивания файла на не-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 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. [code]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" characters String 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);[/code]
Дима, твоя популярность растет)
Дима, твоя популярность растет)
Hi Dmirty Shnyrev, I have been trying to send an email with pdf attachment from Salesforce using SendGrid.
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.
[quote="salesforcedeveloper"]Hi Dmirty Shnyrev, I have been trying to send an email with pdf attachment from Salesforce using SendGrid.[/quote] 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 [color=red]UPDATE[/color] 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. [code] ... 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> ... [/code] So with last example from the article and this additional data you should receive right request for SendGrid.
Дима, твоя популярность растет)
Сам поражаюсь
[quote="Gres"]Дима, твоя популярность растет)[/quote] Сам поражаюсь :D
Ты бы ответил товарищу!))
Ты бы ответил товарищу!))
Ну так ответил
Кстати хорошая новость - спросил разрешения выложить рабочий пример у директора на github!
Получил добро
Скоро ссылку скину.
Этот товарищ кстати уже не первый кто спрашивает! Просто он по ходу самый настырный. Даже сюда умудрился написать. Я это сообщения разве что в Вконтакте не видел
Ну так ответил :D Кстати хорошая новость :) - спросил разрешения выложить рабочий пример у директора на github! Получил добро :D Скоро ссылку скину. Этот товарищ кстати уже не первый кто спрашивает! Просто он по ходу самый настырный. Даже сюда умудрился написать. Я это сообщения разве что в Вконтакте не видел :D
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!
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 [color=red]multiple files[/color] to the same email address? Do I need include multiple headers as below? [code]header += '--'+boundary+'\r\nContent-Disposition: form-data; name="files[receipt.pdf]";\nContent-Type: application/pdf';[/code] Please help me ! Thanks!
I shared full example under my company Github account!
https://github.com/Kaptio/SalesforceToSendgridWithAttachmentsExample
Please enjoy it
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. :-)
Hi Dmitry Shnyrev, Thank you so much for your help. It is working now. :-)