sendgrid / sendgrid-php

The Official Twilio SendGrid PHP API Library
https://sendgrid.com
MIT License
1.49k stars 623 forks source link

batch send of multiple emails to multiple addresses #378

Closed dommermuth closed 7 years ago

dommermuth commented 7 years ago

Hello, I don't think what I want to do is possible, but wanted to confirm.

I'd like to batch send custom email content to multiple people.

So, 1 unique email, per address.

I tried using 'substitution' in the personalization object (V3), but substituting an entire email for content breaks the api. Substitution expects a relatively simple string rather than an entire email.

I think I could probably create templates or something at Send Grid to expect custom args, but that won't work me as the emails are already entirely fully formed.

It appears that whether I use curl or this api, there is no way to send SendGrid 1 unique email per subscriber as a batch. Is that correct?

I do see I can do this one at a time very easily, but I think that would take quite a bit more time to process.

Thanks for any info!

thinkingserious commented 7 years ago

Hi @dommermuth,

Can you tell me what was the error you received when you tried to use substitutions in the personalization object?

dommermuth commented 7 years ago

Hello, yes of course.

Maybe this will help identify the problem. If I send this:

$recip = new \SendGrid\Email($email->sender_name, $email->sender_email);
$personalization->addTo($recip);
$personalization->setSubject($email->subject);
$personalization->addSubstitution("%text_content%", "text");
$personalization->addSubstitution("%html_content%", "<p>htmltest</p>");                 
$mail->addPersonalization($personalization);            
$text_content = new \SendGrid\Content("text/plain", "%text_content%");
$mail->addContent($text_content);
$html_content = new \SendGrid\Content("text/html", "%html_content%");
$mail->addContent($html_content);                   
$reply_to = new \SendGrid\ReplyTo("test@example.com");
$mail->setReplyTo($reply_to);

$apiKey = $this->send_grid_key;

$sg = new \SendGrid($this->send_grid_secret);   
$response = $sg->client->mail()->send()->post($mail);                   

var_dump($response->headers());

the response is accepted and the email is sent + received. If I populate the substitution for 'html_content' with a fully formed email (i can share a sample if it helps), then the response is "Bad Request" -

array(16) { [0]=> string(22) "HTTP/1.1 100 Continue " [1]=> string(1) " " [2]=> string(25) "HTTP/1.1 400 Bad Request " [3]=> string(14) "Server: nginx " [4]=> string(36) "Date: Mon, 10 Apr 2017 22:10:20 GMT " [5]=> string(31) "Content-Type: application/json " [6]=> string(20) "Content-Length: 252 " [7]=> string(23) "Connection: keep-alive " [8]=> string(22) "X-Frame-Options: DENY " [9]=> string(58) "Access-Control-Allow-Origin: https://sendgrid.api-docs.io " [10]=> string(35) "Access-Control-Allow-Methods: POST " [11]=> string(87) "Access-Control-Allow-Headers: Authorization, Content-Type, On-behalf-of, x-sg-elas-acl " [12]=> string(28) "Access-Control-Max-Age: 600 " [13]=> string(75) "X-No-CORS-Reason: https://sendgrid.com/docs/Classroom/Basics/API/cors.html " [14]=> string(1) " " [15]=> string(0) "" }

Thank you for looking into this. Please let me know if I can add anything.

Kurt

thinkingserious commented 7 years ago

Hi @dommermuth,

Could you please let me know the underlying error message, like so? Thanks!

dommermuth commented 7 years ago

ah. ok. So, the try/catch didn't trigger a 'catch', but I dumped the response and in the response it said:

"Substitutions are limited to 10000 bytes per personalization block."

As I mentioned above, I'm trying to substitute in an entire fully formed email. It appears that 10kb limit won't me do that.

Any chance of that changing? Or is there another means of doing this?

Thanks again.

thinkingserious commented 7 years ago

Hi @dommermuth,

I see, thanks for taking the time to dig deeper. I was thinking that perhaps there was a formatting issue with the substitution.

In your case, I believe this is a usage issue that is not directly related to this SDK. For that type of issue, our support team is best equipped to help you. They can be reached at https://support.sendgrid.com.

Thanks!

Elmer

dommermuth commented 7 years ago

Ok. Support message sent. Thanks Elmer.

CyberPunkCodes commented 7 years ago

Why are you using substitutions for your entire HTML and text content?

Since there is a byte limit on substitutions, you want as little in them as possible. Substitutions are meant to be used for things like: name, username, user id, etc...

Put 99% of your email's content where it belongs, in the content added via addContent(). Then replace only what you need with substitutions.

Also, the text version must come before the html content, or it won't send. You have it fine now, just letting you know in case you move things around and stumble on another issue.

dommermuth commented 7 years ago

As I said, because the email is already fully formed. The application is currently coded to work with AWS SES and I'd rather not make radical changes. Additionally, some times large blocks of content are different within the same send. It could conceivably exceed the byte limitation even with what you're suggesting.

Thank you though.

CyberPunkCodes commented 7 years ago

Your only allowed 10k bytes per personalization object. Which is actually a LOT of room, when your not putting entire blocks of HTML in them.

I checked a few emails that I had, to get an idea of what the size would have been for them using your method. I checked the size using https://mothereff.in/byte-counter as well as putting the data in a text file, and checking it's size (which matched the website).

Receipt emailed to me (HTML): 55k bytes (over the limit) Email from Github about this thread (HTML): 2,500 bytes

The receipt was a fancier modern template with extensive HTML/CSS/Image markup inside it. The Github notifications are rather simple, like HTML emails that look like text ones. So it depends on how complex your HTML is for your email template.

I use this on a clients site, where he emails a detailed HTML table to all his users. It has about 20-25 substitutions. It sends to thousands of users in like 10 seconds. That is pulling all his users, formatting the payload, the send/receive to sendgrid, and loading the page.

Use templates on sendgrid to wrap as much known/static code as possible. Use sections, footer, everything you can other than substitutions. Then use substitutions for the remaining dynamic data, and as little markup in the substitution as possible.

You say the email is already pre-formatted. So your saying you don't have all the substitutions loaded in variables that you can easily use in sendgrid? If you are the one generating this Amazon SES pre-formatted email, then you need to reflow your logic and have those variables kick off to your SendGrid process. If your not in control of that Amazon SES email being generated, then you would need to parse the email and strip out the data you need and ignore the HTML. Just taking the source from the Amazon email and tossing it into sendgrid personalizations is taking the easy way out... and it isn't going to work.

I doubt they will raise the 10kb limit, and definitely not in a timely manner for it to even matter to you.

That is the ONLY way to get your email to send.