I started a project using symfony 4 and the mailer doesn't work, however it should be easy.
before you ask, if i copy past the login and password from my code i'm able to log into my mail account, also i also tried with a netcourrier mail account, also the 2 way authentification is not active and i allowed less secure app to access the mail account.
Here's my conf:
in my .env:
MAILER_URL=gmail://*******#gmail.com:********#localhost
in my controller:
public function contact( \Swift_Mailer $mailer){
$message = (new \Swift_Message('Hello Email'))
->setFrom('*****#gmail.com')
->setTo('*******#gmail.com')
->setBody(
$this->renderView(
// templates/emails/registration.html.twig
'email/registration.html.twig',
array('url' => $url)
),
'text/html'
);
$mailer->send($message);
return $this->render(
'email/index.html.twig');}
and the error i get doing so is :
Connection could not be established with host smtp.gmail.com [ #0]
The problem is your connection SMTP with google, This is correct:
MAILER_URL=smtp://smtp.gmail.com:587?encryption=tls&username=userGmail&password=PassGmail
I have it defined as a service in App/Services, this is the code
<?php
namespace App\Services;
class Enviomail {
private $mailer;
public function __construct(\Swift_Mailer $mailer)
{
$this->mailer = $mailer;
}
public function sendEmail($to, $subject, $texto) {
$message = (new \Swift_Message($subject))
->setFrom('juanitourquiza#gmail.com')
->setTo($to)
->setBody(($texto),'text/html');
return $this->mailer->send($message);
}
}
And to use it I call it from the controller
use App\Services\Enviomail;
........
public function mailsolucion(Request $request, Enviomail $enviomail) {
if ($request->isMethod('POST')) {
$nombre=$request->get("nombre");
$email=$request->get("email");
$numero=$request->get("numero");
$empresa=$request->get("empresa");
$solucion=$request->get("solucion");
if (($nombre=="")||($email=="")||($numero=="")||($empresa=="")){
$this->addFlash(
'alert alert-danger',
'Toda la informaciĆ³n es obligatoria'
);
return $this->redirectToRoute('registro');
}
$emailreceptor="juanitourquiza#gmail.com";
$asunto="Soluciones gruporadical.com";
$texto=$this->renderView(
'emails/soluciones.html.twig',
array(
'nombre' => $nombre,
'email' => $email,
'numero' => $numero,
'empresa' => $empresa,
'solucion' => $solucion,
)
);
$enviomail->sendEmail($emailreceptor,$asunto, $texto);
$this->addFlash(
'alert alert-success',
'Pronto nos pondremos en contacto.'
);
return $this->redirectToRoute('registro');
}
return $this->render('AppBundle:App:contacto.html.twig');
}
Works perfect on Symfony 4.x
I think this is not an issue with the mailer, but with gmail. I copied your steps to try to connect through the smtp server of gmail, but got the same error. When using a different MAILER_URL (a different smtp-server) in the .env file, everything works like it should.
Related
I want to send email verification when a user signs up with a new Email Address. So at the Register Controller I added this:
public function register(Request $request)
{
if(Session::has('email')){
return Redirect::back()->withErrors(['msg' => 'Email was already sent to you, please check the spam folder too.']);
}else{
$validatedEmail = $request->validate([
'user_input' => 'required|unique:users,usr_email|regex:/(.+)#(.+)\.(.+)/i|max:125|min:3',
],[
'user_input.required' => 'You must enter this field',
'user_input.unique' => 'This email is already registered',
'user_input.regex' => 'This email is not correct',
'user_input.max' => 'Maximum length must be 125 characters',
'user_input.min' => 'Minimum length must be 3 characters',
]);
$register = new NewRegisterMemberWithEmail();
return $register->register();
}
}
So if the email was valid, it will call a helper class NewRegisterMemberWithEmail which goes like this:
class NewRegisterMemberWithEmail
{
public function register()
{
try{
$details = [
'title' => 'Verify email'
];
Mail::to(request()->all()['user_input'])->send(new AuthMail($details));
Session::put('email',request()->all()['user_input']);
return redirect()->route('login.form');
}catch(\PDOException $e){
dd($e);
}
}
}
So it used to work fine and correctly sends the email for verification, but I don't know why it does not send email nowadays.
In fact I have tested this with different mail service providers and for both Yahoo & Gmail the email did not received somehow!
But for local mail service provider based in my country the email was sent properly!
I don't know really what's going on here because the logic seems to be fine...
So if you know, please let me know... I would really really appreciate any idea or suggestion from you guys.
Also here is my AuthMail Class if you want to take a look at:
class AuthMail extends Mailable
{
use Queueable, SerializesModels;
public $details;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($details)
{
$this->details = $details;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->subject('Sitename')->view('emails.AuthMail');
}
}
Once I was faced same problem when I was used Gmail as smtp.
Reason:
when we used our Gmail password directly in smtp settings then due to some Gmail policies it'll be blocked after sometime (months) and stopped email sending.
Solution:
we need to create an app-password from our Gmail security and use that password in smtp settings. below google article will guide:
How to create app-password on gmail
.env smtp setting for laravel:
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=<your-email>
MAIL_PASSWORD=<app-password>
MAIL_ENCRYPTION=tls
I hope that'll help you.
If you use google mail to send email then we have the same problem.
On May 30, 2022 Google stop supporting less secure applications or third party application.
This is I think the reason why your send mail does not work (consider this answer if you use google mail as mail sender)
I was having issues when sending email, especially to gmail accounts. So I have changed my approach and overcome that issue.
Please check my answer below
Laravel Email
Example Mail Class
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Symfony\Component\Mime\Email;
class OrderInfoMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public $data;
public function __construct($data)
{
$this->data = $data;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$this
->subject('Order Confirmation')
->from('noreply#app.xxx.co.uk', 'XXX Portal')
->view('orders.templates.order-form')
->with([
'name' => $this->data->name,
'sales_representative_name' => $this->data->sales_representative_name,
'sales_representative_phone' => $this->data->sales_representative_phone,
"items" => $this->data->items,
"address" => $this->data->address,
"net" => $this->data->net,
"payment" => $this->data->payment,
"balance" => $this->data->balance,
]);
$this->withSymfonyMessage(function (Email $message) {
$message->getHeaders()->addTextHeader(
'X-Mailer', 'PHP/' . phpversion()
);
});
return $this;
}
}
Usage
$email = 'a#b.com'; // pls change
$name = 'ab';// pls change
$data = new \stdClass();
$data->name = $name;
$data->sales_representative_name = \App\User::find(Auth::user()->id)->name;
$data->sales_representative_phone = \App\User::find(Auth::user()->id)->phones->first()->number;
$data->items = $order_items;
$data->address = $address;
$data->net = $net;
$data->payment = $payment;
$data->balance = $balance;
Mail::to($email)->send(new \App\Mail\OrderInfoMail($data));
I don't think the issue is your code. I think it is related to you sending practices. A solution is to use a service that is designed to send emails like SparkPost (full disclosure I work for SparkPost). There are many others. These services can help you make sure you are following email best practices.
You can make this work without an email service but at the very least you should verify you are following the best practices presented by MAAWG: https://www.m3aawg.org/published-documents
I am using SwiftMailer in my Symfony 5 project to send emails.
I was using it in a controller to send a reset password e-mail, and everything was working.
I am now trying to use it in a MessageHandler, here is the code I am now using :
final class SendEmailMessageHandler implements MessageHandlerInterface
{
private $mailer;
public function __construct(\Swift_Mailer $mailer)
{
$this->mailer = $mailer;
}
public function __invoke(SendEmailMessage $message)
{
$mail = (new \Swift_Message())
->setFrom($message->getFrom())
->setTo($message->getTo())
->setBody($message->getBody(), $message->getContentType())
->setSubject($message->getSubject());
$response = $this->mailer->send($mail);
}
}
The response is ok, but the mail never reach my mailbox.
Here is how I am dispatching my SendEmailMessage :
class AskResetPassword extends AbstractController
{
use ResetPasswordControllerTrait;
private $resetPasswordHelper;
private $validator;
private $bus;
public function __construct(ResetPasswordHelperInterface $resetPasswordHelper, ValidatorInterface $validator, MessageBusInterface $bus)
{
$this->resetPasswordHelper = $resetPasswordHelper;
$this->validator = $validator;
$this->bus = $bus;
}
public function __invoke($data)
{
$emailConstraints = new Assert\Email();
$email = $data->getEmail();
if ($email) {
$errors = $this->validator->validate($email, $emailConstraints);
if (count($errors) === 0) {
return $this->processPasswordReset($email);
} else {
return new JsonResponse(['success' => false, 'error' => 'Invalid E-Mail format'], 404);
}
}
}
private function processPasswordReset($email)
{
$user = $this->getDoctrine()->getRepository(User::class)->findOneBy([
'email' => $email,
]);
$this->setCanCheckEmailInSession();
if (!$user) {
// Do not reveal whether a user account was found or not.
return new JsonResponse(['success' => true], 200);
}
try {
$resetToken = $this->resetPasswordHelper->generateResetToken($user);
} catch (ResetPasswordExceptionInterface $e) {
return new JsonResponse(['success' => false, 'error' => 'There was a problem handling your password reset request - ' . $e->getReason()]);
}
$message = new SendEmailMessage($email);
$message->setFrom('from.from#from.from');
$message->setBody(
$this->renderView('reset_password/email.html.twig', [
'resetToken' => $resetToken,
'tokenLifetime' => $this->resetPasswordHelper->getTokenLifetime()
])
);
$message->setSubject('Votre demande de changement de mot de passe');
$this->bus->dispatch($message);
return new JsonResponse(['success' => true], 200);
}
}
Here is my swiftmailer.yaml :
swiftmailer:
url: '%env(MAILER_URL)%'
spool: { type: 'memory' }
Can you help me ?
The answer is "DO NOT spool emails unless you want to process them later".
Check docs Spool Emails
A spooler is a queue mechanism which will process your message queue one by one. This was introduced when swift-mailer was rewritten and added back to symfony. In combination with Messenger Component which provides abstract interface MessageBusInterface, it would delegate to right backend service which can be smtp relay, push notification or any other type of RPC which may trigger actions on separate web services.
As symfony adds new capabilities to the message bus, this feature was added to utilize it for message queues & other services where transactional emails and notifications are processed separately.
To process your spool simply run :
APP_ENV=prod php bin/console swiftmailer:spool:send
In typical installation spooling is disabled, when you enable spooling in memory, it will wait till request is finished and kernel is about to exit. If you are using anything else to debug that terminates kernel halfway or there are other components & parts of application that keeps kernel in memory, events will not be triggered and mail will not be sent.
You can check whole documentation here : Sending Emails
I cant remember the exact reason why and at the time of posting this I'm struggling to find the answer but the swiftmailer type must be file instead of memory. This GitHub issue references this. You can also see how to change the type here.
this may look stupid but I am wondering how to test the function that sends an email from Gmail, NOT from command line because that thing works fine. I want how to call the function that sends an emails . I have followed this tutorial .
My config/packages/imap.yaml is
imap:
connections:
example_connection:
mailbox: "{imap.gmail.com:993/imap/ssl}INBOX"
username: "kadrad26666#gmail.com"
password: "password"
another_connection:
mailbox: "{localhost:143}INBOX"
username: "username"
password: "password"
attachments_dir: "%kernel.root_dir%/../var/imap/attachments"
server_encoding: "UTF-8"
My Index function in IndexController is
public function index($name, \Swift_Mailer $mailer) {
$message = (new \Swift_Message('Hello Email'))
->setFrom('kadrad26666#gmail.com')
->setTo('kadrad26666#gmail.com')
->setBody(
$this->renderView(
// templates/emails/registration.html.twig
'emails/registration.html.twig',
array('name' => $name)
),
'text/html'
)
;
$mailer->send($message);
return $this->render('registration.html.twig'); }
my twig is as follows
<div class="box box-solid alert-block">
<div class="box-header">
<h3 class="box-title"></h3>
</div>
<div class="box-body">
{{render( controller('App\\Controller\\IndexController::index("hello")') ) }}
</div>
</div>
It is exactly in index($name, \Swift_Mailer $mailer) that I am stuck , what parameters should I give.
I don't think this is the most efficient approach in doing this. Including template fragments works in some cases but I doubt whether this is the correct approach for this particular scenario.
But, if you really want to do this, you can create an Swift_Mailer object and pass on to the twig as a parameter,
// Create the Mailer using your created Transport
$mailer = new Swift_Mailer($transport);
// Create a message
$message = (new Swift_Message('Wonderful Subject'))
->setFrom(['john#doe.com' => 'John Doe'])
->setTo(['receiver#domain.org', 'other#domain.org' => 'A name'])
->setBody('Here is the message itself')
;
// Pass the $mailer to the twig as a parameter.
More :- https://swiftmailer.symfony.com/docs/messages.html
What I would do is create a controller function which calls a services function to send the email and embed that controller call to the twig (Like you are already doing). In that Controller function you do not want to accept parameters. Let the auto-wiring handle the arguments needs for services.
Cheers.
I set up a contact form which sends an email on completion using Laravel notifications, however it doesn't look like anything is being sent.
ROUTES
Route::post('/contact', 'ContactController#store');
CONTROLLER
public function store()
{
request()->validate([
'name' => 'required|max:255',
'email' => 'required|email|unique:contacts|max:255',
'message' => 'required|max:2000',
]);
$contact = Contact::create(
request()->only([
'name',
'email',
'message',
])
);
User::first()->notify(new SendContactNotification($contact));
return back()->with('success', 'Thank you, I will be in touch as soon as I can');
}
NOTIFICATION
protected $contact;
public function __construct($contact)
{
$this->contact = $contact;
}
public function toMail($notifiable)
{
return (new MailMessage)
->line($this->contact->name)
->line($this->contact->email)
->line($this->contact->message);
}
I do get the success message when I run it. However, nothing appears in my Mailtrap. Here's the mail section of the sanitised .env file:
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=username
MAIL_PASSWORD=password
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS='admin#test.com'
MAIL_FROM_NAME='admin'
I can't see what I have done wrong. I also tried type hinting the contact in the notification like so:
public function __construct(Contact $contact)
{
$this->contact = $contact;
}
That didn't work unfortunately. I also thought it might be something to do with my computer not being set up to send emails using php, but I was under the impression that the env file would take care of that.
The contacts are being stored in the database ok, but no emails are being sent. Would anyone be able to help?
It was the port in the env file, I changed it to:
MAIL_PORT=465
and it worked!
I knew port 2525 wasn't working because of this answer: https://stackoverflow.com/a/45418259/5497241
For user identification,I need to send the url of localhost via mail in php codeigniter . . I also need to pass the token which I had generated for that user along with the url. My user need to be verified by clicking that link which must be identified by the corresponding token. And I have no idea about passing variables via url . . How could I proceed my code?
My code follows. .
<?php
class Site_model extends CI_Model
{
public function __construct()
{
parent:: __construct();
$this->load->database();
}
public function insert($token)
{
$data = array(
'name'=>$this->input->post('name'),
'email'=>$this->input->post('email'),
'phone'=>$this->input->post('phone'),
'date_of_birth'=>$this->input->post('dob'),
'user_type'=>$this->input->post('utype'),
'token'=>$token,
);
$this->db->insert('tbl_user',$data);
$email=$this->input->post('email');
$config = array(
'protocol' => 'smtp',
'smtp_host' => 'ssl://smtp.googlemail.com',
'smtp_port' => '465',
'smtp_user' => 'someone#gmail.com',
'smtp_pass' => 'something',
'mailtype' => 'html',
'starttls' => true,
'newline' => "\r\n"
);
$this->load->library('email',$config);
$this->email->From("someone#gmail.com");
$this->email->to($email);
$this->email->subject('test');
$this->email->message("worked");
$this->email->send();
if($this->email->send()) {
echo '<script>alert("Email sent successfully")</script>';
} else {
$this->email->print_debugger();
}
}
}
?>
To pass data along with a URL you can use URI segments.
In your situation the easiest thing to do would probably to be to use GET parameters. To use these you would output the link as normal and then append a parameter to the end like:
http://yoursite.com/user/verify/**token**
This example would be for if you had a user controller with a function called verify. The method signature would be something like:
public function verify($token = NULL) { ... }
The last part of the URL will populate $token which you can then use in the verify function to check the user is valid and perform any actions you need to.
You could always re-route a URL to an alternative method through routes.php if you needed to as well.
Simply pass this link with the token inserted into the email so that when the user clicks on it then the verify method runs with the necessary parameters.