This topic is locked
[SOLVED]

 Email API services

1/16/2021 6:58:17 AM
PHPRunner General questions
D
david22585 author

Has anyone been able to integrate email API from services like mailgun or others into PHPRunner? The standard SMTP is okay, but sending large amounts of email takes some time and isn't as reliable, and most shared hosts don't allow the use of external SMTP servers for spam reasons.

admin 1/16/2021

We use SendGrid to send some of our emails. We use SMTP for single emails and they have a web-based UI that helps you to prepare and send a newsletter to the list of subscribers. Never really used they REST API but here is the link: https://sendgrid.com/docs/api-reference/
Check 'MAIL SEND' link on the left for the easiest example of email sending, they provide the sample PHP code as well.
PS. Never heard of web hosting companies blocking external for spam reasons. Usually, it is the other way around. Some people may open an account to send spam through their SMTP. External SMTP is someone else's problem.

D
david22585 author 1/16/2021



We use SendGrid to send some of our emails. We use SMTP for single emails and they have a web-based UI that helps you to prepare and send a newsletter to the list of subscribers. Never really used they REST API but here is the link: https://sendgrid.com/docs/api-reference/
Check 'MAIL SEND' link on the left for the easiest example of email sending, they provide the sample PHP code as well.
PS. Never heard of web hosting companies blocking external for spam reasons. Usually, it is the other way around. Some people may open an account to send spam through their SMTP. External SMTP is someone else's problem.


I'll try to use the external SMTP, but this is what my host says:

You cannot use external SMTP servers to send e-mail messages if you have one of the following hosting packages:

Web hosting (Startup, Drive, Turbo Boost, or Turbo Max)

Reseller hosting

Managed WordPress hosting


We may have to send up to 150 emails at a time to individual people. I was thinking of writing it to a DB, and having a cronjob send them out, but then the cronjob is limited as well to how often it can run. It seems that my host has no limit to using API for mail sending, which is why I was looking at that. Going to play around over the next week, just wasn't sure if anyone has implemented it or not.

A
acpan 1/16/2021

Most hosting providers worry their IP ranges are blocked or blacklisted automatically by SPAM detection Providers, especially people who request to open emails ports, if you host your email servers on your host and need to open email ports to communicate with other email servers in the world. If you are not careful, the IP will be blacklisted within hours after spam detected from your host, and it is done by SPAM detection "robots" automatically. So Providers are pretty paranoid about email ports, because they will have less IPs to provide.
Just for sending out via SMTP (without receiving emails) should be fine. However, my experience is, they (at least 2 to 3 providers i used) even blocked the remote SMTP server port 25 and other email ports from my hosts, until I requested and acknowledged their anti-spamming agreement.
You can check if your IP or any port, domain is blocked/blacklisted using, eg. mxtoolbox.com

This is always the first thing i check, when i create a new cloud instance. I will recreate if the assigned IP is blacklisted in mxtoolbox.
On using the Email API Provider, I tried SendGrid and MailJet, they have both SMTP and REST API.

API wise, it is just like sending a PHP Curl.
I would normally submit from the PHP Web page (eg. PHPRunner generated site) that sends CLI (Linux) command to a PHP script (sendmail.php) that runs in the background, so that it will not freeze the web page if it takes too long.
Below is a sample script just to give you an idea, that i put in my host to receive my email task, the script is also available at the online help once you have an account with them.
You should also put in place security measures, like restricting the IP or login session:


sendmail.php
<?php
/////////////////////////////////////////////////////////////////////

// Default PHP time_limit will fail for > 250 concurrent email posts,

// so extend it to 900 (15min). Default 200 email posts is still ok

// without changing the time limit on my test.

///////////////////////////////////////////////////////////////////////
set_time_limit(900); // 15 min
require 'vendor/autoload.php';

use \Mailjet\Resources;
$subject = $_REQUEST["subject"] ?? "Your email flight plan!";

$textpart = $_REQUEST["textpart"] ?? "Dear passenger 1, welcome to Mailjet! May the delivery force be with you!";

$htmlpart = $_REQUEST["htmlpart"] ?? "<h3>Dear passenger 1, welcome to <a href=\"https://www.mailjet.com/\">Mailjet</a>!</h3><br />May the delivery force be with you!";
$from_email = "custcare@XXX.com";

$from_name = "Customer Care";

$to_email = "XXX@gmail.com";

$to_name = "Customer";

// $to_email2 = "passenger2@mailjet.com";

// $to_name2 = "passenger 2";

// $cc_email = "copilot@mailjet.com";

// $cc_name = "Copilot";

// $bcc_email = "XXX@XXX.com";

// $bcc_name = "XXX, OT";
$mj = new \Mailjet\Client(getenv('MJ_APIKEY_PUBLIC'), getenv('MJ_APIKEY_PRIVATE'),true,['version' => 'v3.1']);
$body = [

'Messages' => [

[

'From' => [

'Email' => $from_email ,

'Name' => $from_name

],

'To' => [

[

'Email' => $to_email,

'Name' => $to_name

]

],

'Bcc' => [

[

'Email' => $bcc_email,

'Name' => $bcc_name

]

],

'Subject' => $subject,

'TextPart' => $textpart,

'HTMLPart' => $htmlpart

]

]

];
$response = $mj->post(Resources::$Email, ['body' => $body]);

$response->success() && var_dump($response->getData());
// var_dump($response);
///////////////////////////////////////////////////////////////////////////////////

set_time_limit(180); // put back to normal value

///////////////////////////////////////////////////////////////////////////////////
/* Example of Response from the API: */

/*

API response
{

"Messages": [

{

"Status": "success",

"To": [

{

"Email": "passenger1@mailjet.com",

"MessageUUID": "123",

"MessageID": 456,

"MessageHref": "https://api.mailjet.com/v3/message/456";

},

{

"Email": "passenger2@mailjet.com",

"MessageUUID": "124",

"MessageID": 457,

"MessageHref": "https://api.mailjet.com/v3/message/457";

}

],

"Cc": [

{

"Email": "copilot@mailjet.com",

"MessageUUID": "125",

"MessageID": 458,

"MessageHref": "https://api.mailjet.com/v3/message/458";

}

],

"Bcc": [

{

"Email": "air-traffic-control@mailjet.com",

"MessageUUID": "126",

"MessageID": 459,

"MessageHref": "https://api.mailjet.com/v3/message/459";

}

]

}

]

}

*/
D
david22585 author 2/7/2021



Most hosting providers worry their IP ranges are blocked or blacklisted automatically by SPAM detection Providers, especially people who request to open emails ports, if you host your email servers on your host and need to open email ports to communicate with other email servers in the world. If you are not careful, the IP will be blacklisted within hours after spam detected from your host, and it is done by SPAM detection "robots" automatically. So Providers are pretty paranoid about email ports, because they will have less IPs to provide.
Just for sending out via SMTP (without receiving emails) should be fine. However, my experience is, they (at least 2 to 3 providers i used) even blocked the remote SMTP server port 25 and other email ports from my hosts, until I requested and acknowledged their anti-spamming agreement.
You can check if your IP or any port, domain is blocked/blacklisted using, eg. mxtoolbox.com

This is always the first thing i check, when i create a new cloud instance. I will recreate if the assigned IP is blacklisted in mxtoolbox.
On using the Email API Provider, I tried SendGrid and MailJet, they have both SMTP and REST API.

API wise, it is just like sending a PHP Curl.
I would normally submit from the PHP Web page (eg. PHPRunner generated site) that sends CLI (Linux) command to a PHP script (sendmail.php) that runs in the background, so that it will not freeze the web page if it takes too long.
Below is a sample script just to give you an idea, that i put in my host to receive my email task, the script is also available at the online help once you have an account with them.
You should also put in place security measures, like restricting the IP or login session:


I know it's been a few weeks, but I've tried a few ways and cannot get something like this to work. Are there ways to get this code to work in the after add event or before add event?



require 'vendor/autoload.php';

use \Mailjet\Resources;

$mj = new \Mailjet\Client('keycode','keycode',true,['version' => 'v3.1']);

$body = [

'Messages' => [

[

'From' => [

'Email' => "email@address.com",

'Name' => "David"

],

'To' => [

[

'Email' => "email@address.com",

'Name' => "David"

]

],

'Subject' => "Greetings from Mailjet.",

'TextPart' => "My first Mailjet email",

'HTMLPart' => "<h3>Dear passenger 1, welcome to <a href='https://www.mailjet.com/'>Mailjet</a>!</h3><br />May the delivery force be with you!",

'CustomID' => "AppGettingStartedTest"

]

]

];

$response = $mj->post(Resources::$Email, ['body' => $body]);

$response->success() && var_dump($response->getData());


It says that we can use PHP code in events, but this code throws an error: Parse error: syntax error, unexpected 'use' (T_USE) in .......
What I need is a way to use email API on events to send mail. I just cannot figure it out for the life of me. This is for a magnitude of different things, such as a forum, updates, notifications, messages, etc.

A
acpan 2/7/2021

>>It says that we can use PHP code in events, but this code throws an error: Parse error: syntax error, unexpected 'use' (T_USE) in .......
First you should do a simple isolated test (not from PHPR app), drop in the sample scripts into your web server, make a simple test page, and send email. If "use" error persist, you likely did not load the library correctly.

  1. Check your path if you load the maijet library correctly. Try using mailjet composer version if needed.
  2. After loaded correctly, send again and view mailjet response by dumping everything out, add this to your last line:
    var_dump($response);
  3. If you get a response from mailjet but not receiving email (good, you are almost there!). Login to mailjet and check if mailjet only permit you to send from a pre-registered email. I am not sure but one of them I used asked me to register my sending email address, else all my emails will be stucked in their portal.
  4. If you get no response at all from mailjet and you are sure you use mailjet port 80, your host provider may have also blocked mailjet domain in an unlikely practice, since your account is stated to be limited by your host provider, then it is time to find another provider or upgrade your plan.
    If it works, than there are many ways to call from the events. Eg, convert the sample script to a function, include the sample script in your PHPR header.php and call the function from the events
    or Keep the sample script as a local REST service (like my above example) to receive your PHP Curl call from the events. Ensure security in place if you do so, else it will become an open relay to spams.

D
david22585 author 2/7/2021



>>It says that we can use PHP code in events, but this code throws an error: Parse error: syntax error, unexpected 'use' (T_USE) in .......
First you should do a simple isolated test, drop in the sample scripts into your web server, make a simple test page, and send email. If "use" error persist, you likely did not load the library correctly.

  1. Check your path if you load the maijet library correctly. Try using mailjet composer version if needed.
  2. After loaded correctly, send again and view mailjet response by dumping everything out, add this to your last line:
    var_dump($response);
  3. If you get a response from mailjet but not receiving email (good, you are almost there!). Login to mailjet and check if mailjet only permit you to send from a pre-registered email. I am not sure but one of them I used asked me to register my sending email address, else all my emails will be stucked in their portal.
  4. If you get no response at all from mailjet and you are sure you use mailjet port 80, your host provider may have also blocked mailjet domain in an unlikely practice, since your account is stated to be limited by your host provider, then it is time to find another provider or upgrade your plan.
    If it works, than there are many ways to call from the events. Eg, convert the sample script to a function, include the sample script in your PHPR header.php and call the function from the events
    or Keep the sample script as a local REST service (like my above example) to receive your PHP Curl call from the events. Ensure security in place if you do so, else it will become an open relay to spams.


I found that sendgrid had a pretty good layout to use their API, but I'm still having some issues that I can't quite pinpoint. This is what I'm using now:

$email = new \SendGrid\Mail\Mail();

$email->setFrom("test@mail.com", "Example User");
$rs = DB::Query("SELECT * FROM members");

while( $data = $rs->fetchAssoc() ){

if( $data["email"] )

$maillist[] = '"'.$data["email"].'" => "'.$data["name"].'"';

}

$emaillist = implode(", ", $maillist);

$tos = "[".$emaillist."]";
$email->addTos($tos);

$email->setSubject("Sending with Twilio SendGrid is Fun");

$email->addContent("text/plain", "and easy to do anywhere, even with PHP");

$email->addContent(

"text/html", "<strong>Number: </strong>".$values["contact"].""

);

$sendgrid = new \SendGrid('keycodehere');

try {

$response = $sendgrid->send($email);

print $response->statusCode() . "\n";

print_r($response->headers());

print $response->body() . "\n";

} catch (Exception $e) {

echo 'Caught exception: '. $e->getMessage() ."\n";

}


This doesn't work at all when trying to create the array of e-mails. I may need to contact sendgrid on this, but if I take out the code to make the array of e-mails from the database, I get the following error:

Fatal error: Uncaught exception 'SendGrid\Mail\TypeException' with message '"$toEmails" must be an array. Got: ["email1@mail.com" => "Name 1", "email2@mail.com" => "Name 2", "email3@test.com" => "Name 3"]'


It seems that the array is fine. If I enter all the e-mails into the code as opposed to the mysql query, it works perfectly fine, to which the format is the exact same as I show above. So making progress on how to use the sendgrid API. It works if you have the e-mail data put into the code, just not with a dynamic query yet.

A
acpan 2/8/2021

Seems your array is not form correctly as what SendGrid expects.

A
acpan 2/8/2021

Try this:



$tos_array = [];
$email = new \SendGrid\Mail\Mail();

$email->setFrom("test@mail.com", "Example User");
$rs = DB::Query("SELECT * FROM members");

while( $data = $rs->fetchAssoc() ){

if( $data["email"] )
// assign email as key and name as value to the array $tos_array

// each new email in the loop forms a new key/value element in the array

$tos_array[ $data["email"] ]= $data["name"];

}

...
print_r($tos_array);

/* should give

Array ( [test+test1@example.com] => Example User1

[test+test2@example.com] => Example User2

[test+test3@example.com] => Example User3

)

*/
mail->addTos($tos_array);
D
david22585 author 2/8/2021



Try this:


That worked perfectly, thanks!!!
Marking this as solved, I want to provide the full code for others.
On the After App Init event, I have this to include the sendgrid code:

require_once(getabspath("include/sendgrid/sendgrid-php.php"));


On the after record add event, I have the following:



$email = new \SendGrid\Mail\Mail();

$email->setFrom("sender@mail.com", "From User");
$rs = DB::Query("SELECT * FROM members");

while($data = $rs->fetchAssoc()){

if($data["email"])

$tos_array[$data["email"]]= $data["name"];

}
$email->addTos($tos_array);

$email->setSubject("Sending with Twilio SendGrid is Fun");

$email->addContent("text/plain", "and easy to do anywhere, even with PHP");

$email->addContent(

"text/html", "<strong>Number: </strong>".$values["contact"].""

);
$sendgrid = new \SendGrid('sendgrid_API_keycode_here');

try {

$response = $sendgrid->send($email);

print $response->statusCode() . "\n";

print_r($response->headers());

print $response->body() . "\n";

} catch (Exception $e) {

echo 'Caught exception: '. $e->getMessage() ."\n";

}


You can use the standard $values in the email content as well. Next up, making it work where it send each email individually so everyone can't see who received the email. Debating on doing this code in a loop for each email, or if there is some other way to send the emails individually through sendgrid from the array.

A
acpan 2/8/2021

Great!
>making it work where it send each email individually so everyone can't see who received the email.
Just use "bcc" (blind carbon copy) as addresses for customers, and "to" set to your own email address.
For inspiration:



$email = new \SendGrid\Mail\Mail();

$email->setFrom("sender@mail.com", "From User");
$tos_array["sender2@mail.com"]= "From User2";

$email->addTos($tos_array);

// Or use addTo method for single email without array: $email->addTo("sender2@mail.com", "From User2");
// Form the array for bcc

$rs = DB::Query("SELECT * FROM members");

while($data = $rs->fetchAssoc()){

if($data["email"])

$bccs_array[$data["email"]]= $data["name"];

}

$email->addBccs($bccs_array);

...


Refer to SendGrid kitchen sink example for all options.
Good luck!

D
david22585 author 2/20/2021

Just wanted to add another one in for others to reference, or for others to build off of to maybe make it better. I didn't want to use the BCC method. I tried many times to make it work to where individual emails were sent and it didn't show the other peoples e-mail addresses. I couldn't get the sendmail examples to work, but I did get it to work by going through a loop for each email queried. I know this probably takes longer, and I hope that others can maybe build from this and add to it to make it better.



$rs = DB::Query("SELECT * FROM members WHERE email != ''");

while( $data = $rs->fetchAssoc()){

$arr = explode(",",$data["email"]);

for ($i=0;$i<count($arr);$i++){

$email = new \SendGrid\Mail\Mail();

$email->setFrom("Sender@domain.com", "Example User");

$email->addTo($arr[$i]);

$email->setSubject("Sending with Twilio SendGrid is Fun");

$email->addContent("text/plain", "and easy to do anywhere, even with PHP");

$email->addContent(

"text/html", "<strong>Number: </strong>".$values["contact"].""

);
$sendgrid = new \SendGrid('API_key');

try {

$response = $sendgrid->send($email);

print $response->statusCode() . "\n";

print_r($response->headers());

print $response->body() . "\n";

} catch (Exception $e) {

echo 'Caught exception: '. $e->getMessage() ."\n";

}

}

}


This loops through every email address and sends an individual API request for each one.