Got parse error with Mail config headers in ZF2 - php

I use Zend\Mail\Transport\Smtp to send an email. Below is my code.
use Zend\Mail\Message;
use Zend\Mail\Transport\Smtp as SmtpTransport;
use Zend\Mail\Transport\SmtpOptions;
public function smtpConfig($message)
{
$transport = new SmtpTransport();
$options = new SmtpOptions(array(
'name' => localhost,
//'host' => 10.92.32.81,
'port' => 25,
));
$transport->setOptions($options);
echo $transport->send($message);
}
public function sendMail($to,$from,$subject,$body)
{
$message = new Message();
$message->addTo($to)
->addFrom($from)
->setSubject($subject)
->setBody($body);
$this->smtpConfig($message);
}
I have configured smtp in local system and I'm able to receive email without any warnings/low priority errors. I delivered this code for project testing. Mail functionality is working fine in their system but in browser console following warning/error is displayed and I dont see this error in my local setup.
Parse error: syntax error, unexpected '[' in D:\applications\www-php\kiosquebo\vendor\zendframework\zend-mail\src\Headers.php on line 39
Any solution given is appreciated.

According to the line in the file you're getting the error, PHP is failing to parse this line:
protected $headersKeys = [];
The only issue that is possible here is that your PHP version is too old and does not work with the [] array definer.
You should update your PHP version to at least 5.4.

Related

Laravel - changing email settings on the fly is not working

All of my email settings for my app are stored in the database. The user has the option to change those settings, and it all works great. But I am trying to setup a "Send Test Email" function to allow users to test their settings before saving them. When they submit the form for to send the test email, the email is sent via the original settings rather than the new settings.
The form is submitted to SettingsController.php
// Send a test email
public function sendTestEmail(Request $request)
{
Log::info(config('mail.host'));
// Just to check the current email host - shows the proper host
// from the database - i.e. smtp.mailtrap.io
// Make sure that all of the information properly validates
$request->validate([
'host' => 'required',
'port' => 'required|numeric',
'encryption' => 'required',
'username' => 'required'
]);
// Temporarily set the email settings
config([
'mail.host' => $request->host,
'mail.port' => $request->port,
'mail.encryption' => $request->encryption,
'mail.username' => $request->username,
]);
// Only update the password if it has been changed
if(!empty($request->password))
{
config(['mail.password' => $request->password]);
}
// Try and send the test email
try
{
Log::info(config('mail.host'));
// Just to check the new setting - this also shows the correct
// email host - which is the newly assigned one via the form
// i.e. smtp.google.com
Mail::to(Auth::user()->email)->send(new TestEmail());
return response()->json([
'success' => true,
'sentTo' => Auth::user()->email
]);
}
catch(Exception $e)
{
Log::notice('Test Email Failed. Message: '.$e);
$msg = '['.$e->getCode().'] "'.$e->getMessage().'" on line '.
$e->getTrace()[0]['line'].' of file '.$e->getTrace()[0]['file'];
return response()->json(['message' => $msg]);
}
}
In my TestEmail class, I have brought it down to the basics
namespace App\Mail;
//use Illuminate\Bus\Queueable; // Commented out to be sure it is not queuing
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
//use Illuminate\Contracts\Queue\ShouldQueue; // Commented out to be sure it is not queuing
class TestEmail extends Mailable
{
// use Queueable, SerializesModels; // Commented out to be sure it is not queuing
/**
* Create a new message instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->subject('Test Email From '.config('app.name'))->markdown('email.testEmail');
}
}
Even though the logs are showing the updated smtp host for the config setting, the message is still being sent out via the original setting - i.e. smtp.mailtrap.io.
TL;DR
An immediate answer to your question, please refer to this following code tested on Laravel 5.8:
$transport = app('swift.transport');
$smtp = $transport->driver('smpt');
$smpt->setHost('PUT_YOUR_HOST_HERE');
$smpt->setPort('THE_PORT_HERE');
$smpt->setUsername('YOUR_USERNAME_HERE');
$smpt->setPassword('YOUR_PASSWORD_HERE');
$smpt->setEncryption('YOUR_ENCRYPTION_HERE');
Why setting up config on the fly does not work?
In laravel architecture, it is first had all the service providers registered and that includes the MailServiceProvider. See your config/app.php
// inside config/app.php
...
Illuminate\Mail\MailServiceProvider::class,
...
And the config will be loaded before it reaches your route, see Illuminate\Mail\TransportManager
/**
* Create an instance of the SMTP Swift Transport driver.
*
* #return \Swift_SmtpTransport
*/
protected function createSmtpDriver()
{
$config = $this->app->make('config')->get('mail');
// The Swift SMTP transport instance will allow us to use any SMTP backend
// for delivering mail such as Sendgrid, Amazon SES, or a custom server
// a developer has available. We will just pass this configured host.
$transport = new SmtpTransport($config['host'], $config['port']);
if (isset($config['encryption'])) {
$transport->setEncryption($config['encryption']);
}
//... rest of the code
}
so the way I deal with this using TransportManager's drivers method to pick up desired driver and set the config I want, since above code we can see lots of usage of its api.
Hope this helps
I am facing the same issue I just use
config(['mail.driver' => 'smtp']);
when I Debug
dd(config('mail.driver'));
Configuration is all fine
I just review a comment here by kfirba
I'm pretty sure that the issue is caused because when laravel registers the mailer key in the IoC Container it uses the original config. Changing that won't cause laravel to re-define the mailer key.
If you take a look at MailerServiceProvider you will see that it is deferred which means that once you call it, it will instantiate the object and it uses a singleton. I believe that you've used the Mail::send() method elsewhere in the application which led to registering the mailer key in the application. Since it's a singleton it won't read your configuration files again when you re-use it.
Solution:
config(['mail.driver' => 'smtp']);
(new Illuminate\Mail\MailServiceProvider(app()))->register();
Works on Laravel 8
You can set/change any configuration on the fly using Config::set:
Config::set('key', 'value');
So, to set/change the port in mail.php you may try this:
Config::set('mail.port', 587); // default
Note: Configuration values that are set at run-time are only set for the current request, and will not be carried over to subsequent requests
When your app instance sends its first email the Laravel MailManager resolves a new mailer, using the current config values, and caches it by adding it to an internal mailers array. On each subsequent mail that you send, the same cached mailer will be used.
The MailManager has a method to clear its mailer cache:
Mail::forgetMailers();
Now when you send another mail the MailManager must resolve a new mailer, and it will re-read your config while doing so.

Laravel sending email

I am trying to send an email from my application that uses the Laravel framework. I have installed Sximo as a theme for working with Laravel and the application is running on Amazon AWS. All seems to be good with the setup as it is working as intended.
I have a API setup on *C:\xampp\htdocs\public\api\savequestionnaire.php * that receives data from a mobile application and saves the data to a MySQL table. This also is working as intended.
The idea is that if the API receives some data, an email is generated to a predefined email address. With that, I have a file for receiving the data, writing it to a database and then generating the email as below.
For the Mail section I am following the example on the Laravel website from HERE
savequestionnaire.php
<?php
$json = file_get_contents('php://input');
$questionnairevalues = json_decode($json, true);
$position = $questionnairevalues['position'];
$question_one = $questionnairevalues['question_one'];
$question_two = $questionnairevalues['question_two'];
$question_three = $questionnairevalues['question_three'];
$question_four = $questionnairevalues['question_four'];
$question_five = $questionnairevalues['question_five'];
$query = "INSERT INTO tb_q (position, question_one, question_two, question_three, question_four, question_five) "
. "VALUES('$position', '$question_one', '$question_two', '$question_three', '$question_four', '$question_five')";
$result = $mysqli->query($query) or die($mysqli->error.__LINE__);
if ($result) {
echo 'Success';
// Getting error here
Mail::send('emails.contact.blade', $position, function ($message) {
$message->from('myEmail#test.com', 'Laravel');
$message->to('myOtherEmail#test.com');
});
echo '\r\nMail sent success';
}
else {
echo 'Error';
}
mysqli_close($mysqli);
When I run the above code I get the error: "Success
Fatal error: Class 'Mail' not found in C:\xampp\htdocs\public\api\savequestionnaire.php on line 56"
I have also tried adding
use Mail;
to the top of the file but then I get the error: "Warning: The use statement with non-compound name 'Mail' has no effect in C:\xampp\htdocs\public\api\savequestionnaire.php on line 2"
How do I go about implementing the Mail feature correctly using Laravel?
I have also tried using PHP's built in
mail('myEmail#test.com', 'My Subject', 'My message');
function. This generates no errors - but no emails are sent or received.
add this at top of controller:
use Illuminate\Support\Facades\Mail;
In your case directly use :
\Illuminate\Support\Facades\Mail::send('emails.contact.blade', $position, function ($message) {
instead of Mail::send('emails.contact.blade', $position, function ($message) {
In Your Config / app.php Check whether there is
Illuminate\Mail\MailServiceProvider::class,
under providers. And Check Under Aliases you have
'Mail' => Illuminate\Support\Facades\Mail::class,
Edit :
According to the Error, it is looking the facade inside the questionnaire.php you are now in. So try putting this code inside of a controller.
To create a controller, in the terminal type,
php artisan make:controller controllerName
If this page is standalone, you have to use composer to be able to use Mail:
add
require 'vendor/autoload.php';
at the top of your page (replace the path for matching the location of your vendor/autoload.php file

Zend\Mail fails with Gmail, but SwiftMailer lacks a file transport for development/testing. what to do?

I have successfully used Zend_Mail from ZF1 to connect to a GMail account using SMTP, but have not been able to get it to work with Zend\Mail. The following produced a "Connection timed out" exception:
use Zend\Mail\Message;
use Zend\Mail\Transport\Smtp as SmtpTransport;
use Zend\Mail\Transport\SmtpOptions;
$transport = new SmtpTransport();
$options = new SmtpOptions([
'host' => 'smtp.gmail.com',
'connection_class' => 'login',
'connection_config' => [
'username' => 'my_username#gmail.com',
'password' => 'redacted',
'port' => 587,
'ssl' => 'tls',
],
]);
$transport->setOptions($options);
$message = new Message();
$message->addTo('recipient#example.org')
->setFrom('me#example.org')
->setSubject('hello, fool!')
->setBody("testing one two three! time is now ".date('r'));
$transport->send($message);
However! The very same connection parameters work fine when I do the equivalent of the above with PHP Swiftmailer, and also with Python, and also with the older Zend_Mail. All of this of course in the same environment (my Ubuntu 14.04 box). So, I think there must be an issue with Zend\Mail -- or perhaps more accurately Zend\Mail\Transport\Smtp.
Unfortunately I am not enough of a hero (and lack the skills) to dig into Zend\Mail\Transport\Smtp and fix it, so I turned next to Swiftmailer (http://swiftmailer.org/). And it works just great,
$transport = Swift_SmtpTransport::newInstance('smtp.gmail.com', 587, 'tls');
$transport->setUsername('my_username#gmail.com')
->setPassword('redacted');
$mailer = Swift_Mailer::newInstance($transport);
$message = Swift_Message::newInstance();
$message->setSubject("testing from Swiftmailer")
->setFrom("me#example.org")
->setTo('recipient#example.org')
->setBody("yadda yadda blah blah blah!");
$result = $mailer->send($message); // nice and easy!
but lacks one nice feature: Zend\Mail has a File transport that simply dumps your message to a file, very handy for development and testing, when you don't really want to send email messages to anyone.
What to do? I am familiar with the configuration trick of setting an "environment" environment variable to "development", "production", etc., and making my code decide how to configure itself accordingly. But in my thought experiments so far, this gets a little awkward.
One idea: subclass Swift_Mailer and override send() to simply write the message to disk, and consult the $environment to decide whether to instantiate the real thing or the subclass that doesn't really send.
But I would love to hear some other ideas and suggestions.
For swiftmailer you can use SpoolTransport with a FileSpool to store messages to filesystem.
Example (by Norio Suzuki):
/**
* 270-transport-spool-file.php
*/
require_once '../vendor/autoload.php';
require_once './config.php';
// POINT of this sample
$path = FILE_SPOOL_PATH;
$spool = new Swift_FileSpool($path);
$transport = Swift_SpoolTransport::newInstance($spool);
$mailer = Swift_Mailer::newInstance($transport);
$message = Swift_Message::newInstance();
$message
->setFrom(MAIL_FROM)
->setTo(MAIL_TO)
->setSubject('SpoolTransport (file) sample')
->setBody('This is a mail.')
;
// Serialized Swift_Message objects were spooled to $path
$result = $mailer->send($message);
OK, this is a two-part answer and you can pick.
Answer #1: don't worry about writing to a file, just use Swiftmailer's undocumented Swift_NullTransport like so:
$transport = new Swift_NullTransport::newInstance();
/* and so forth */
The send() method of Swift_Transport_NullTransport (parent of Swift_NullTransport) does nothing but act as though it succeeded, which in my case is about as good as dumping to a file.
Answer #2: roll your own somehow, e.g., either (a) by extending one of the Transport classes and overriding send(), or (b) writing another Transport whose send() writes to a file, and then making a PR on Github for the benefit of all sentient beings.

Postmarkapp sending email using template PHP class

I am trying to send a email using postmarkapp api in php, I have managed to get it to send plain emails. I have uploaded the class to the same directory as index.php but the 'use' function seems to give me a error which is out of my knowledge.
Error:
Parse error: syntax error, unexpected '.', expecting identifier (T_STRING) in /public_html/index.php on line 5
Index.php
// Import the Postmark Client Class.
use Postmark\Models\PostmarkAttachment;
use Postmark\PostmarkClient\.php;
// Create Client
$client = new PostmarkClient("MY API KEY - CENSORED");
// Make a request
$sendResult = $client->sendEmailWithTemplate(
"sender#example.com",
"recipient#example.com",
TEMPLATEID-CENSORED,
[
"product_name" => "product_name_Value",
"name" => "name_Value",
"action_url" => "action_url_Value",
"username" => "username_Value",
"sender_name" => "sender_name_Value",
"product_address_line1" => "product_address_line1_Value",
"product_address_line2" => "product_address_line2_Value",
]);
Same directory Postmark/ I have this class (official class)
https://github.com/wildbit/postmark-php/tree/master/src/Postmark
Thanks for taking the time to read, greatly appreciated.
I think you need 'use Postmark\PostmarkClient;' instead of 'use Postmark\PostmarkClient.php;'

use PHP Swiftmailer in Symfony 1.4's Cron Jobs?

I am using Symfony 1.4 with Propel as ORM. i have configured web server schedulers to trigger a mailing function at every 1Hour. To send mails i am using PHP Swift mailer class, and not the symfony's inbuild Swiftmailer(default in 1.3,1.4). But while using it is giving me error..
as "Catchable fatal error: Argument 1 passed to Swift_Transport_EsmtpTransport::__construct() must implement interface Swift_Transport_IoBuffer, none given in /home/msconslt/sfprojects/test/lib/mailClasses/classes/Swift/Transport/EsmtpTransport.php on line 64".
The code that i am using...
require_once(dirname(__FILE__).'/../../config/ProjectConfiguration.class.php');
$configuration =ProjectConfiguration::getApplicationConfiguration('frontend', 'dev', true);
// Remove the following lines if you don't use the database layer
$databaseManager = new sfDatabaseManager($configuration);
//Create the Transport
$transport = Swift_SmtpTransport::newInstance('smtp.gmail.com', 465, "ssl")
->setUsername('myid#gmail.com')
->setPassword('mypassword')
;
//Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);
//Create a message
$message = Swift_Message::newInstance("Test Mail")
->setFrom(array('myid#gmail.com' => 'Harry'))
->setTo(array('someid#gmail.com'))
->setBody('<html>'.
'<head></head>'.
'<body> <span>Dear, </span><br/> Hi there..</body>'.
'</html>',
'text/html'
);
$mailer->send($message);
is there any other way to send mail through Cron jobs??
Yes. See the relevant part of the 1.4 book: Sending an email from a task.
This problem is because you need add this reference in your taks :
requiere_once dirname(__FILE__) . '/../vendor/symfony/lib/vendor/swiftmailer/swift_required.php

Categories