I want to create a register/login window with Laravel version 8. When I try to register I get the following error message:
Swift_RfcComplianceException
Address in mailbox given [ee3...] does not comply with RFC 2822, 3.6.2.
MailController:
class MailController extends Controller
{
public static function sendSignupEmail($name, $email, $verification_code){
$data = [
'name' => $name,
'verification_code' => $verification_code
];
Mail::to($email)->send(new SignupEmail($data));
}
}
SignupEmail:
public function __construct($data)
{
$this->email_data = $data;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->from(env('MAIL_USERNAME'), 'website')->subject("Welcome to my Website!")->view('mail.signup-email', ['email_data' => $this->email_data]);
}
.env (To test it I use mailtrap)
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=ee3...
MAIL_PASSWORD=ddc...
MAIL_ENCRYPTION=tls
I use xampp v.3.2.4.
The problem is I don't understand the error. I don't have a lot of Laravel/PHP experience but I've done similar things before and it always worked.
Could it be a version conflict?
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 have an exception whe I try to reset password in my app. I use Symfony 4.4 and and installed "symfonycasts/reset-password-bundle": "^1.13", the controller is the next:
class ResetPasswordController extends AbstractController {
use ResetPasswordControllerTrait;
private $resetPasswordHelper;
private $entityManager;
public function __construct(ResetPasswordHelperInterface $resetPasswordHelper, EntityManagerInterface $entityManager)
{
$this->resetPasswordHelper = $resetPasswordHelper;
$this->entityManager = $entityManager;
}
/**
* Display & process form to request a password reset.
*
* #Route("", name="app_forgot_password_request")
*/
public function request(Request $request, MailerInterface $mailer, TranslatorInterface $translator): Response
{
$form = $this->createForm(ResetPasswordRequestFormType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
return $this->processSendingPasswordResetEmail(
$form->get('email')->getData(),
$mailer,
$translator
);
}
return $this->render('reset_password/request.html.twig', [
'requestForm' => $form->createView(),
]);
}
private function processSendingPasswordResetEmail(string $emailFormData, MailerInterface $mailer, TranslatorInterface $translator): RedirectResponse
{
$user = $this->entityManager->getRepository(User::class)->findOneBy([
'email' => $emailFormData,
]);
// Do not reveal whether a user account was found or not.
if (!$user) {
return $this->redirectToRoute('app_check_email');
}
try {
$resetToken = $this->resetPasswordHelper->generateResetToken($user);
} catch (ResetPasswordExceptionInterface $e) {
return new Response(json_encode(['message' => $e->getMessage()]), 500, ['Content-Type' => 'application/json']);
// If you want to tell the user why a reset email was not sent, uncomment
// the lines below and change the redirect to 'app_forgot_password_request'.
// Caution: This may reveal if a user is registered or not.
//
// $this->addFlash('reset_password_error', sprintf(
// '%s - %s',
// $translator->trans(ResetPasswordExceptionInterface::MESSAGE_PROBLEM_HANDLE, [], 'ResetPasswordBundle'),
// $translator->trans($e->getReason(), [], 'ResetPasswordBundle')
// ));
return $this->redirectToRoute('app_check_email');
}
$email = (new TemplatedEmail())
->from(new Address('rgutierrez#greicodex.com', 'Yoke Integration Suite'))
->to($user->getEmail())
->subject('Your password reset request')
->htmlTemplate('reset_password/email.html.twig')
->context([
'resetToken' => $resetToken,
])
;
$mailer->send($email);
// Store the token object in session for retrieval in check-email route.
$this->setTokenObjectInSession($resetToken);
return $this->redirectToRoute('app_check_email');
}
}
I called the request function from app and the problem occured when the processSendingPasswordResetEmail function is executed in the line "$resetToken = $this->resetPasswordHelper->generateResetToken($user);" , the function is not executed and returns the following exception:
An exception occurred while executing a query: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'expires_at' in 'where clause'
I followed the installation guide to add reset password feature on the next page:
https://symfony.com/doc/4.4/security/reset_password.html
https://github.com/symfonycasts/reset-password-bundle
I did not add any function, in fact everything is created by the guide as indicated and I do not know why the error occurs, could someone help me solve the problem please.
If you execute php bin/console doc:sch:update --dump-sql, have you SQL updates ?
Regards,
Could you put ResetPasswordHelperInterface $resetPasswordHelper, EntityManagerInterface $entityManager directly in your processSendingPasswordResetEmail function via Dependency Injection and remove your constructor ? You can remove the variable declaration too.
This will fix the issue.
Regards
I am trying send email verification links to user when they register but I get a message Authentication required and mail isn't sent. I tried using mailtrap for demo and sendgrid which I will be using in production but the message was the same. This is how I a going about it
After running composer require guzzlehttp/guzzle I updated my env file like this
# MAIL_DRIVER=smtp
# MAIL_HOST=smtp.mailtrap.io
# MAIL_PORT=2525
# MAIL_USERNAME=mailtrap_username
# MAIL_PASSWORD=mailtrap_password
# MAIL_ENCRYPTION=tls
MAIL_DRIVER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=sendgrid_username
MAIL_PASSWORD=sendgrid_password
MAIL_ENCRYPTION=tls
In the controller, I want to send the mail after a user is successfully created like this
...
use App\Mail\VerifyEmail;
...
use Illuminate\Support\Facades\Mail;
public function register(Request $request)
{
// create and store new user record
$user = User::create([
'username' => $request->username,
'password' => bcrypt($request->password)
]);
// send user email verification link
Mail::to($user->username)->send(new VerifyEmail());
}
VerifyMail.php
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class VerifyEmail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$from = 'support#fromus.com';
$name = 'custom name';
$subject = 'Welcome! Confirm Your Email';
return $this->from($from, $name)
->subject($subject)
->view('auth.verify');
}
}
Following the documentation for email verification https://laravel.com/docs/5.8/verification#verification-routing I added the Auth::routes(['verify' => true]) to api.php file like this
<?php
// Register routes for email verification
Auth::routes(['verify' => true]);
Route::prefix('v1')->group(function () {
// protected routes
Route::middleware('auth:api')->group(function () {
Route::get('products', 'ProductController#index'); // get products
});
});
Route::fallback(function () {
return response()->json(['error' => 'Not Found'], 404);
});
Why am I getting the Authentication required error message and how can I fix it?
First i removed Auth::routes(['verify' => true]) from the api.php file and added it in the web.php.
Then I ran php artisan config:cache to cache changes made to the env file. Fixed
I am using built in laravel auth functionality.Its working fine.I am trying to override following two functionality.
1.send forgot password email using mandrill.
2.send verification email while registering account.
Can any one help me to solve this issue
My aim is to use mandril instead of default email
I can see auth built in methods but i didnt got idea how i can override that
trait ResetsPasswords
{
use RedirectsUsers;
/**
* Display the password reset view for the given token.
*
* If no token is present, display the link request form.
*
* #param \Illuminate\Http\Request $request
* #param string|null $token
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function showResetForm(Request $request, $token = null)
{
return view('auth.passwords.reset')->with(
['token' => $token, 'email' => $request->email]
);
}
/**
* Reset the given user's password.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function reset(Request $request)
{
$this->validate($request, $this->rules(), $this->validationErrorMessages());
// Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response.
$response = $this->broker()->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
}
);
// If the password was successfully reset, we will redirect the user back to
// the application's home authenticated view. If there is an error we can
// redirect them back to where they came from with their error message.
return $response == Password::PASSWORD_RESET
? $this->sendResetResponse($response)
: $this->sendResetFailedResponse($request, $response);
}
As answered by Mahfuzal, Laravel comes with a bunch of mail drivers out of the box. So just update your .env file to use the right driver.
As for sending a verification email when creating an account, you just need to override the postRegister() function inside the Auth/AuthController like so:
public function postRegister(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
$confirmation_code = str_random(30);
$newUser = new User;
$newUser->username = $request->username;
$newUser->email = $request->email;
$newUser->password = bcrypt($request->password);
$newUser->confirmation_code = $confirmation_code;
$newUser->save();
$data = array('confirmation_code' => $confirmation_code, 'username' => $request->username);
Mail::send('emails.verify', $data, function ($message) use ($newUser){
$message->to($newUser->email, $newUser->username);
$message->subject('Please verify your email address');
});
return redirect('/auth/login');
}
This will execute the above code when registering a user rather than what Laravel does default out of the box so just tweak it to your needs.
You then just need to create a function that will check the token and verify their account when they click the link. For that, I use something similar to what is explained here.
Laravel provides drivers for SMTP, Mailgun, Mandrill, Amazon SES,
PHP's mail function, and sendmail, allowing you to quickly get started
sending mail through a local or cloud based service of your choice.
Open your .env file and change following by your Mandrill credentials and then you're good to go.
MAIL_DRIVER=mandrill
MAIL_HOST=
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
You can create your own reset method in the controller that uses the trait to override the method in the trait.
I assumed that by default the Log::info calls wouldn't log in production, but they are still coming in.
Im setting production using my .env file
APP_ENV=production
APP_DEBUG=false
Ive tried these commands as well, but no luck
composer dump-autoload
php artisan cache:clear
php artisan optimize
Am i missing something?
For anyone still finding this thread (8 years later):
Configure your log channels in config/logging.php file
Set "level" parameter for your log channel to a .env variable
Example:
'channels' => [
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => 'Lumen Log',
'emoji' => ':boom:',
'level' => env('LOG_LEVEL', 'error'),
]
]
Now you can set the LOG_LEVEL variable in your .env file for each environment
Well, I think that it's too late to search for all the Log::info() and do the proposed answer by #jon__o
if (App::environment('local', 'staging')) {
Log::info($error);
}
But you can still do something. You can override the default Laravel logger instance with your own implementation.
Go to your ApplicationServiceProvider and override the log instance with a custom one:
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->registerLogger();
}
/**
* Register the logger instance in the container.
*
* #return MyCustomWriter
*/
protected function registerLogger()
{
$this->app->instance('log', $log = new MyCustomWriter(
new Monolog($this->app->environment()), $app['events'])
);
$log->dontLogInfoOnEnvironmnets(['production', 'staging', 'other']);
return $log;
}
Now you can create your custom writer by just extending the Laravel's Writer and overriding the info() method.
class MyCustomWriter extends \Illuminate\Log\Writer
{
protected $dontInfoOn = [];
/**
* Log an informational message to the logs.
*
* #param string $message
* #param array $context
* #return void
*/
public function info($message, array $context = [])
{
// Since we are providing the app environment to the Monolog instance in out ApplicationServiceProvider
// we can get the environment from the Monolog getName() method
if(!in_array($this->monolog->getName(), $this->dontInfoOn)) {
return parent::info($message, $context);
}
}
/**
* Don't log info() on the supplied environments .
*
* #param array $environments
* #return void
*/
public function dontLogInfoOnEnvironmnets(array $environments)
{
$this->dontInfoOn = $environments;
}
}
This way, you can still keep you Log::info on testing environments without checking every time.
Only the displaying of errors will be suppressed when your application is not in debug mode. The Log::info() function will always log when called.
The simple solution is for you to wrap that Log::info() function in something like this:
if (App::environment('local', 'staging')) {
Log::info($error);
}
Be sure to include the App facade use App; at the top of your file. Alternatively you can use the app() helper to get the environment: $environment = app()->environment();.