I'm using Swiftmailer to send email. I had installed
+ "guzzlehttp/guzzle": "^6.3"
+ "swiftmailer/swiftmailer": "^6.0".
I create controller and route for it. But it has issue "Call to undefined method Swift_SmtpTransport::newInstance()". Please check my code and guide me how to fix it? Thanks so much
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Swift_Mailer;
use Swift_MailTransport;
use Swift_Message;
class EmailController extends Controller
{
public function sendEmail(){
// Configuration
$smtpAddress = 'smtp.zoho.com';
$port = 465;
$encryption = 'ssl';
$yourEmail = 'ptc#gmail.com';
$yourPassword = '********';
// Prepare transport
$transport = \Swift_SmtpTransport::newInstance($smtpAddress, $port, $encryption)
->setUsername($yourEmail)
->setPassword($yourPassword);
$mailer = \Swift_Mailer::newInstance($transport);
// Prepare content
$view = View::make('email_template', [
'message' => '<h1>Hello World !</h1>'
]);
$html = $view->render();
// Send email
$message = \Swift_Message::newInstance('Test')
->setFrom(['ptc#gmail.com' => 'Our Code World'])
->setTo(["hik#gmail.com" => "mail#mail.com"])
// If you want plain text instead, remove the second paramter of setBody
->setBody($html, 'text/html');
if($mailer->send($message)){
echo "Check your inbox";
}
echo "Something went wrong :(";
}
}
Found in GitHub issues, for SwiftMailer "^6.0"
::newInstance() method has been deprecated, along with
Swift_MailTransport.
Try to change:
\Swift_SmtpTransport::newInstance()
\Swift_Mailer::newInstance()
to:
new \Swift_SmtpTransport();
new \Swift_Mailer()
More information about:
The GitHub issue
Documentation for ^6 version, read Basic Usage
Don't overcomplicate things.
You are rewriting something that comes bundled with laravel.
https://laravel.com/docs/5.5/mail
No need to setup swiftmailer yourself, just use the laravel classes and set the smtp credentials on
config/mail.php
It can be as easy as
Mail::raw('Text to e-mail', function($message)
{
$message->from('us#example.com', 'Laravel');
$message->to('foo#example.com')->cc('bar#example.com');
});
Or you can go fancy and use a view to make your template.
Mail::send('emails.welcome', $data, function($message)
{
$message->from('us#example.com', 'Laravel');
$message->to('foo#example.com')->cc('bar#example.com');
$message->attach($pathToFile);
});
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 trying to use Mail function in Laravel. Heres the code
public function basic_email(){
$data = array('name'=>"Virat Gandhi");
Mail::send(['text'=>'mail'], $data, function($message) {
$message->to('shanipasrooria#gmail.com', 'Tutorials Point')->subject
('Laravel Basic Testing Mail');
$message->from('m.usman5991#gmail.com','Virat Gandhi');
});
echo "Basic Email Sent. Check your inbox.";
}
I have made changes in .env file. Set everything, Heres my route.
Route::get('sendbasicemail','MailController#basic_email');
I get the following Error.
InvalidArgumentException in FileViewFinder.php line 137:
View [mail] not found.
You can try this code
Mail::send([], [], function ($message) {
$message->to('shanipasrooria#gmail.com', 'Tutorials Point')
->subject('subject')
->setBody('some body', 'text/html');
});
you can try this
$html = '<h1>Hi, welcome Virat!</h1>';
Mail::send([], [], function ($message) use ($html) {
$message->to('shanipasrooria#gmail.com', 'Tutorials Point')
->subject('Laravel Basic Testing Mail')
->from('m.usman5991#gmail.com','Virat Gandhi')
->setBody($html, 'text/html'); //html body
or
->setBody('Hi, welcome Virat!'); //for text body
});
Mail::send(['text'=>'mail']< here the mail should be a valid view file.
According to API Documentation, the Mailer Class should receive a String, Array Or MailableContract, Those reference a view. So you need to pass a valid view in the send method.
void send(string|array|MailableContract $view, array $data = [], Closure|string $callback = null)
In my app I am trying to send an email using Mail::queue().
I get an exception saying that serialization of closure failed.
ErrorException in SerializableClosure.php line 93: Serialization of
closure failed: Serialization of 'Closure' is not allowed
I have a this as the send function:
public function send()
{
$view = view('emails.welcome');
$data = [
'user' => Auth::user()
];
return $this->mailer->queue($view, $data, function($message){
$message->to($this->to)->subject($this->subject);
});
}
I've only recently begun using Laravel so any help would be great.
The issue it that you're trying to use $this inside Closure.
Please provide parameters $to and $subject using use keyword like in this example:
return $this->mailer->queue($view, $data, function($message) use ($to, $subject) {
$message->to($to)->subject($subject);
});
The issue is using $this inside of the closure.
$this->to and $this->subject are references to fields on the Class and not in the Closure so to fix the code make them local variables and pass them to closure like as below:
public function send()
{
$to = $this->getTo();
$subject = $this->getSubject();
return $this->mailer->queue( $this->getView(), $this->getData(), $this->getData(),
function($message) use($to, $subject) {
$message->to($to)->subject($subject);
});
}
I'm new to coding and Laravel 5.1, and after watching the tutorials by Laracasts I have been creating my own webpage. I came across and error that I cant fix...
Method [send] does not exist.
My code looks like this:
namespace App\Http\Controllers;
use Mail;
use App\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class ContactController extends Controller
{
/**
*
* #param Request $request
*/
public function emailContactForm (Request $request){
$msg = $request->input('message');
$name = $request->input('name');
$email = $request->input('email');
//
$this->validate($request, [
'title' => 'required|max 500',
'name' => 'required',
'email' => 'required',
]);
//
Mail::send(
'emails.contactForm',
[
'message'=>$msg,
'name'=>$name,
],
function($m) use ($email) {
$m->to('jessica.blake#autumndev.co.uk', 'say hi')
->subject('new message')
->from($email);
}
);
//
return;
}
}
I'm trying to use the mail function, which we have now got working, but the send still doesn't? Any suggestions? Thanks!
EDIT: Full stack trace as per laravel log file: http://pastebin.com/ZLiQ7Wgu
At the very first sight, you are calling the controller method send() but you actually named it emailContactForm()
You dont post routes and actions so the quick fix by now is trying to rename emailContactForm to send, despite instead you should probably need to review all your related routing logic.
My system sends a couple of important emails. What is the best way to unit test that?
I see you can put it in pretend mode and it goes in the log. Is there something to check that?
There are two options.
Option 1 - Mock the mail facade to test the mail is being sent. Something like this would work:
$mock = Mockery::mock('Swift_Mailer');
$this->app['mailer']->setSwiftMailer($mock);
$mock->shouldReceive('send')->once()
->andReturnUsing(function($msg) {
$this->assertEquals('My subject', $msg->getSubject());
$this->assertEquals('foo#bar.com', $msg->getTo());
$this->assertContains('Some string', $msg->getBody());
});
Option 2 is much easier - it is to test the actual SMTP using MailCatcher.me. Basically you can send SMTP emails, and 'test' the email that is actually sent. Laracasts has a great lesson on how to use it as part of your Laravel testing here.
"Option 1" from "#The Shift Exchange" is not working in Laravel 5.1, so here is modified version using Proxied Partial Mock:
$mock = \Mockery::mock($this->app['mailer']->getSwiftMailer());
$this->app['mailer']->setSwiftMailer($mock);
$mock
->shouldReceive('send')
->withArgs([\Mockery::on(function($message)
{
$this->assertEquals('My subject', $message->getSubject());
$this->assertSame(['foo#bar.com' => null], $message->getTo());
$this->assertContains('Some string', $message->getBody());
return true;
}), \Mockery::any()])
->once();
For Laravel 5.4 check Mail::fake():
https://laravel.com/docs/5.4/mocking#mail-fake
If you just don't want the e-mails be really send, you can turn off them using the "Mail::pretend(true)"
class TestCase extends Illuminate\Foundation\Testing\TestCase {
private function prepareForTests() {
// e-mail will look like will be send but it is just pretending
Mail::pretend(true);
// if you want to test the routes
Route::enableFilters();
}
}
class MyTest extends TestCase {
public function testEmail() {
// be happy
}
}
If any one is using docker as there development environment I end up solving this by:
Setup
.env
...
MAIL_FROM = noreply#example.com
MAIL_DRIVER = smtp
MAIL_HOST = mail
EMAIL_PORT = 1025
MAIL_URL_PORT = 1080
MAIL_USERNAME = null
MAIL_PASSWORD = null
MAIL_ENCRYPTION = null
config/mail.php
# update ...
'port' => env('MAIL_PORT', 587),
# to ...
'port' => env('EMAIL_PORT', 587),
(I had a conflict with this environment variable for some reason)
Carrying on...
docker-compose.ymal
mail:
image: schickling/mailcatcher
ports:
- 1080:1080
app/Http/Controllers/SomeController.php
use App\Mail\SomeMail;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
class SomeController extends BaseController
{
...
public function getSomething(Request $request)
{
...
Mail::to('someone#example.com')->send(new SomeMail('Body of the email'));
...
}
app/Mail/SomeMail.php
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class SomeMail extends Mailable
{
use Queueable, SerializesModels;
public $body;
public function __construct($body = 'Default message')
{
$this->body = $body;
}
public function build()
{
return $this
->from(ENV('MAIL_FROM'))
->subject('Some Subject')
->view('mail.someMail');
}
}
resources/views/mail/SomeMail.blade.php
<h1>{{ $body }}</h1>
Testing
tests\Feature\EmailTest.php
use Tests\TestCase;
use Illuminate\Http\Request;
use App\Http\Controllers\SomeController;
class EmailTest extends TestCase
{
privete $someController;
private $requestMock;
public function setUp()
{
$this->someController = new SomeController();
$this->requestMock = \Mockery::mock(Request::class);
}
public function testEmailGetsSentSuccess()
{
$this->deleteAllEmailMessages();
$emails = app()->make('swift.transport')->driver()->messages();
$this->assertEmpty($emails);
$response = $this->someController->getSomething($this->requestMock);
$emails = app()->make('swift.transport')->driver()->messages();
$this->assertNotEmpty($emails);
$this->assertContains('Some Subject', $emails[0]->getSubject());
$this->assertEquals('someone#example.com', array_keys($emails[0]->getTo())[0]);
}
...
private function deleteAllEmailMessages()
{
$mailcatcher = new Client(['base_uri' => config('mailtester.url')]);
$mailcatcher->delete('/messages');
}
}
(This has been copied and edited from my own code so might not work first time)
(source: https://stackoverflow.com/a/52177526/563247)
I think that inspecting the log is not the good way to go.
You may want to take a look at how you can mock the Mail facade and check that it receives a call with some parameters.
if you are using Notifcations in laravel you can do that like below
Notification::fake();
$this->post(...);
$user = User::first();
Notification::assertSentTo([$user], VerifyEmail::class);
https://laravel.com/docs/7.x/mocking#notification-fake
If you want to test everything around the email, use
Mail::fake()
But if you want to test your Illuminate\Mail\Mailable and the blade, then follow this example. Say, you want to test a Reminder email about some payment, where the email text should have product called 'valorant' and some price in 'USD'.
public function test_PaymentReminder(): void
{
/* #var $payment SalePayment */
$payment = factory(SalePayment::class)->create();
auth()->logout();
$paymentReminder = new PaymentReminder($payment);
$html = $paymentReminder->render();
$this->assertTrue(strpos($html, 'valorant') !== false);
$this->assertTrue(strpos($html, 'USD') !== false);
}
The important part here is ->render() - that is how you make Illuminate\Mail\Mailable to run build() function and process the blade.
Another importan thing is auth()->logout(); - because normally emails being processed in a queue that run in a background environment. This environment has no user and has no request with no URL and no IP...
So you must be sure that you are rendering the email in your unit test in a similar environment as in production.