cakephp 3.2 email with sendgrid issue - php

I'm having a hard time trying to figure out how to send mails with sendgrid.
this is the code i currently have:
employees controller:
function _sendEmail($id) {
$email = new Email();
try {
$email->from(['coms#me.co' => 'Me'])
->profile('SendGrid')
->to([$id['email'] => $id['full_name']])
->subject("TEST SUBJECT")
->emailFormat("both")
->template('default')
->send('My message');
$this->Flash->success("Message sent.");
} catch (Exception $ex) {
echo 'Exception : ', $ex->getMessage(), "\n";
}
return $this->redirect(['action' => 'index']);
}
I'm working with this plugin I found a few days ago; https://github.com/Iandenh/cakephp-sendgrid... I configured everything as stated in the docs but when I want to send the mail, nothing happens, the function flashes the success message and makes the redirection, but no email is sent.
This is the email transport in the app.php
'EmailTransport' => [
'SendGridEmail' => [
'className' => 'SendGridEmail.SendGrid',
'api_key' => 'API_KEY'
],
and the delivery profile
'Email' => [
'SendGrid' => [
'transport' => 'SendGridEmail',
'template' => 'default',
'layout' => 'default',
'emailFormat' => 'both',
'from' => ['coms#me.co' => 'Me'],
'sender' => ['coms#me.co' => 'Me'],
]
]
I'd really appreciate if someone can point me out any mistake or a possible solution for my problem.

Hi there this might be too late but in case if anyone facing the same issue.
This is working for me
So the first mistake you did is you are using the Email class, with sendgrid you should be using sendgrid Mail method now
I assume you have already installed this package if not go ahead and add it to the composer.json file and update composer
"sendgrid/sendgrid": "~7",
After that you can use sendgrid class for sending emails like shown in example below
protected function sendEmail($to, $subject, $content)
{
$email = new \SendGrid\Mail\Mail();
$email->setFrom(Configure::consume('App.from_email'), Configure::consume('Theme.title'));
$email->setSubject($subject);
$email->addTo($to);
$email->addContent("text/html", 'Your email body');
$sendgrid = new \SendGrid(Configure::consume('App.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";
}
}
You need to replace sendgrid_api_key with your api key. I am using it from my configuration file.

Related

send mail from other configuration if first config fails laravel

I want to create a code such that if one configuration fails to send mail the other config will kick in to send the mail, I have created two configurations, One in the provider which is set on page load the other is a helper function which can be set as we need.
if I set the helper function before sending any mail the function kicks in but if I keep it in try-catch block the helper doesn't work
try {
Mail::to($administrator->email)->send(new ResetPassword($data));
} catch (\Exception $e) {
$mailsenderr = true;
}
if ($mailsenderr) {
$newConfig = new SecondaryMailer;
$newConfig->setmailer();
try {
Mail::to($administrator->email)->send(new ResetPassword($data));
} catch (\Exception $e) {
return [
"status" => 0,
"message" => 'Error sending mail.'
// , "error" => $e->getMessage()
];
}
}
return ["status" => 1, "message" => "Mail sent successflly"];
Figured out how to
Just create a provider and set the code like
$mail = DB::table('mail_variables')->where('mailer_type', 'primary')->where('status', 'active')->first();
try {
$transport = new \Swift_SmtpTransport($mail->host, $mail->port, $mail->encryption);
$transport->setUsername($mail->username);
$transport->setPassword($mail->password);
$mailer = new \Swift_Mailer($transport);
$mailer->getTransport()->start();
} catch (\Swift_TransportException $e) {
$mail = DB::table('mail_variables')->where('mailer_type', 'secondary')->where('status', 'active')->first();
}
$config = array(
'driver' => $mail->driver,
'host' => $mail->host,
'port' => $mail->port,
'from' => array(
'address' => $mail->from_address,
'name' => $mail->from_name
),
'encryption' => $mail->encryption,
'username' => $mail->username,
'password' => $mail->password,
'sendmail' => '/usr/sbin/sendmail -bs',
'pretend' => false,
);
Config::set('mail', $config);

Call to a member function sendEmail() on null

I am using the AWS example to call the AWS SDK for PHP. When converting the code to a function I get the following error: Uncaught Error: Call to a member function sendEmail()
line 41 seems to be the issue: $result = $SesClient->sendEmail([
I have tried removing the result variable and commenting out its usage
When I run the code and its not a function its working fine, I am not sure what I am doing wrong here, and I am sure it could be a simple error.
Thanks for the help in advance
<?php
// If necessary, modify the path in the require statement below to refer to the
// location of your Composer autoload.php file.
require '/vendor/autoload.php';
use Aws\Ses\SesClient;
use Aws\Exception\AwsException;
// Create an SesClient. Change the value of the region parameter if you're
// using an AWS Region other than US West (Oregon). Change the value of the
// profile parameter if you want to use a profile in your credentials file
// other than the default.
$SesClient = new SesClient([
'profile' => 'default',
'version' => '2010-12-01',
'region' => 'us-east-1'
]);
function send_email($recipient, $message, $subject){
// Replace sender#example.com with your "From" address.
// This address must be verified with Amazon SES.
$sender_email = 'sender#gmail.com';
// Replace these sample addresses with the addresses of your recipients. If
// your account is still in the sandbox, these addresses must be verified.
// $recipient_emails = ['recipient1#example.com','recipient2#example.com'];
$recipient_emails = [$recipient];
// Specify a configuration set. If you do not want to use a configuration
// set, comment the following variable, and the
// 'ConfigurationSetName' => $configuration_set argument below.
// $configuration_set = 'ConfigSet';
$subject = $subject;
$plaintext_body = $message.PHP_EOL.'This email was sent with Amazon SES using the AWS SDK for PHP.' ;
$html_body = '<h1>'.$message.'</h1>';
$char_set = 'UTF-8';
try {
$result = $SesClient->sendEmail([
'Destination' => [
'ToAddresses' => $recipient_emails,
],
'ReplyToAddresses' => [$sender_email],
'Source' => $sender_email,
'Message' => [
'Body' => [
'Html' => [
'Charset' => $char_set,
'Data' => $html_body,
],
'Text' => [
'Charset' => $char_set,
'Data' => $plaintext_body,
],
],
'Subject' => [
'Charset' => $char_set,
'Data' => $subject,
],
],
// If you aren't using a configuration set, comment or delete the
// following line
// 'ConfigurationSetName' => $configuration_set,
]);
$messageId = $result['MessageId'];
echo("Email sent! Message ID: $messageId"."\n");
} catch (AwsException $e) {
// output error message if fails
echo $e->getMessage();
echo("The email was not sent. Error message: ".$e->getAwsErrorMessage()."\n");
echo "\n";
}
return 'success';
}
echo send_email('test#gmail.com', 'test', 'test subject');
Try declaring $SesClient inside of the send_email function
It's working without the function as you've declared $SesClient outside the function. Declare it after function - or pass it to the function via
function function send_email($recipient, $message, $subject, $SesClient) {
/* snip */
}
echo send_email('test#gmail.com', 'test', 'test subject', $SesClient);

php foreach function performance problems

php foreach function should send 1 SMS but it sends 2-3 for each contact.
The code should send invitations through email and SMS. But the contacts are receiving sometimes 2 or three invitation at the same time which gets the SMS to be blocked.
public function handle(QRCodeEmail $mail) {
try {
foreach ($this->event->contacts as $eventContact) {
if($eventContact->pivot->sent_date) {
continue;
}
if($eventContact->email) {
$mail->subject = $this->event->name;
$mail->setEmail($eventContact->email);
$mail->setName($eventContact->first_name . ' ' . $eventContact->last_name);
$mail->send([
'name' => $this->event->name ?? '',
'hostName' => $this->event->host_name ?? '',
'suffix' => $eventContact->suffix,
'firstName' => $eventContact->first_name,
'lastName' => $eventContact->last_name,
'data' => $eventContact->pivot->hash,
]);
}
\Curl::to(env('SMS_GATEWAY_URL'))
->withData([
'username' => env('SMS_GATEWAY_USERNAME'),
'password' => env('SMS_GATEWAY_PASSWORD'),
'message' => $this->generateBodyForSms($eventContact, env('INVITATION_LINK') . $eventContact->pivot->hash),
'numbers' => $eventContact->phone,
'sender' => env('SMS_GATEWAY_SENDER'),
])
->post();
(EventsContacts::find($eventContact->pivot->id))->update([
'sent_date' => Carbon::create()->format('Y-m-d H:i:s')
]);
}
$this->job->delete();
} catch (\Exception $e) {
$this->job->delete();
throw new \Exception($e);
}
}
Some possibilities
Maybe you should try array_unique ( http://php.net/manual/en/function.array-unique.php ) (Check the unique_multidim_array function posted in the comments of array_unique.)
Is it possible that you have mulitple records (with distinct "primary key" with the same number ? Then store phone numbers that have already received the SMS and check against that list before sending a new one.
Maybe your exit condition if($eventContact->pivot->sent_date) doesn't work as inteted.

Override CakeEmail destination globally

Is there an easy way to "override" the destination of an email using CakeEmail?
I have a model method that send an email using this piece of code:
$Email = new CakeEmail();
$Email->config('default');
$sent = $Email->template('new-notification')
->subject('A new notification for you')
->viewVars([
'name' => $foo['User']['name'],
'text' => $foo['Notification']['text'],
)
->emailFormat('html')
->to($foo['User']['email'])
->send();
And this configuration:
class EmailConfig
{
public $default = array(
'host' => 'smtp.server.com',
'port' => 587,
'username' => 'user#domain.com',
'password' => 'pwdAsYouKnow',
'from' => array('noreply#domain.com' => 'Company'),
'transport' => 'Smtp'
);
}
As you can see, I send the email for a dynamically defined user's email.
My objective is when I'm developing locally on my machine, to force every call to ->send() to force a destination like developer#domain.com.
I can easily detect if I'm on development, but I don't know how to force in a "master" way to CakeEmail only send to a defined account overriding the one set on the call.
I already tried to set an
'to' => array('developer#domain.com' => 'Dev'),
inside $default but, no success.
I appreciate any help, thanks!
i'm assuming when you are on local machine you run in debug mode, so you can check if debug mode is on then use that to send to different email
if(Configure::read('debug')){
$emailTo = 'developer#domain.com'
}
else{
$emailTo = $foo['User']['email'];
}
then you just use variable for email address:
$sent = $Email->template('new-notification')
->subject('A new notification for you')
->viewVars([
'name' => $foo['User']['name'],
'text' => $foo['Notification']['text'],
)
->emailFormat('html')
->to($emailTo)
->send();

Why Mandrill emails are not sent from development server(localhost)?

I am using Mandrill API to send email.
I have register my send domain and set my DKIM and SPF record properly inside Mandrill Setting page.
Following is my code that is being used to send email:
$template_name = "Test_Schedule_Reminder";
$to_email = "debesh#debeshnayak.com";
$to_name = "Test Email";
$from_email = "contact#debeshnayak.com";
$from_name = "Debesh Nayak";
require_once 'mandrill-api-php/src/Mandrill.php'; //Not required with Composer
try {
$mandrill = new Mandrill('my-mandrill-api-key');
$message = array(
'html' => $html_email_template,
'subject' => $email_title,
'from_email' => $from_email,
'from_name' => $from_name,
'to' => array(
array(
'email' => $to_email,
'name' => $to_name,
'type' => 'to'
)
),
'important' => true,
'track_opens' => true,
'track_clicks' => true,
'inline_css' => true,
'metadata' => array('website' => 'www.debeshnayak.com'),
);
$async = false;
$ip_pool = null;
$send_at = $utc_class_time;
$result = $mandrill->messages->send($message, $async, $ip_pool, $send_at);
print_r($result);
} catch(Mandrill_Error $e) {
// Mandrill errors are thrown as exceptions
echo 'A mandrill error occurred: ' . get_class($e) . ' - ' . $e->getMessage();
// A mandrill error occurred: Mandrill_Unknown_Subaccount - No subaccount exists with the id 'customer-123'
throw $e;
}
I am able to send email when I am sending from my production server.
But when I am trying to send email from localhost I am getting the following error:
Mandrill_HttpError - API call to messages/send failed: SSL certificate problem: unable to get local issuer certificate
So how to avoid this SSL certificate problem when testing mail from localhost using Mandrill API.
Do check library files of Mandrill and search for cURL call that sending out email. Check for "CURLOPT_SSL_VERIFYPEER" parameter of this cURL. Set value to false. It should help you.
I have added the following two line inside call() function of Mandrill.php library file:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
And now I am able to send email from my localhost using Mandrill API.

Categories