I'm having some trouble with sending email using laravel. I've looked around the stackoverflow for solutions but none worked so far. Here's my env and code so far.
MAIL_DRIVER=smtp
MAIL_HOST=smtp.googlemail.com
MAIL_PORT=465
MAIL_USERNAME=myemail.gmail.com
MAIL_PASSWORD=mypassword
MAIL_ENCRYPTION=ssl
MAIL_SETUP=false
MAIL_FROM_ADDRESS=myemail.gmail.com
MAIL_FROM_NAME="Namehere"
and this is my mail.php file
'smtp' => [
'transport' => 'smtp',
'host' => env('MAIL_HOST', 'smtp.googlemail.com'),
'port' => env('MAIL_PORT', 465),
'encryption' => env('MAIL_ENCRYPTION', 'ssl'),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'timeout' => null,
'auth_mode' => null,
],
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'myemail#gmail.com'),
'name' => env('MAIL_FROM_NAME', 'myemail#gmail.com'),
],
Now this is my code. It's just a simple to test the email function. This is the class created in mail folder
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class NewTicketMail extends Mailable
{
use Queueable, SerializesModels;
public $details;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($details)
{
$this->$details;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->subject('Mail from ')->view('emails.new_ticket_mail');
}
}
and this is the route called
Route::get('send-email', function(){
$details = [
'title'=> 'New Ticket Received',
'body' => 'We have received your ticket and will process it. Please do not reply to this
email'
];
\Mail::to('receiver#gmail.com')->send(new \App\Mail\NewTicketMail($details));
return view('emails.thanks');
});
the route works if i commented out the Mail to line. any suggestions? I've been at it for hours.
In your mail class you are accessing a properties property which does not exist.
Rather in your mailable constructor do something like
public function __construct($details){
$this->details = $details;
}
This is for sure one issue. As laravel will throw an unknown property error.
P.s. make sure your env has debug as true if you are not seeing errors in your logs.
Related
I´m traying to use my new serviceProvider into mail.php because i need get values from database not .env i can show one solution in this site that one person creaed a serviceProvider and get all data that he needed.
My question is, how i can use this provider into mail.php?
my provider:
public function register()
{
if (\Schema::hasTable('app_settings')) {
$mail = DB::table('app_settings')->first();
if ($mail) //checking if table is not empty
{
$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);
}
}
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
mail.php
for example: 'driver' => env('MAIL_DRIVER', 'smtp'),
how i can call driver of provider into driver mail.php
thanks for help, rewards
You can't do it, and it's not a good idea.
The simplest way is to override your config after everything was loaded.
You can use your AppServiceProdiver.php file, and in the boot() function :
public function boot()
{
// adapt of course...
$yourConfig = \DB::select('SELECT * FROM your_config_table');
config()->set([
'app.mail.driver' => $yourConfig[0]->value
]);
}
I want to send emails to 100 users. Mail::send() is taking too much load time and isn't able to cover all emails of users. I'm trying to use Mail::queue() in my application, but I'm getting the error below while running
php artisan queue:listen.
[ErrorExcepton] Undefined Property :
SuperClosure\SerializableClosure::$binding.
Updated .env file with QUEUE_DRIVER = database.
Please help me find the solution to resolve this. Also, I am using the same code to run background jobs, using Laravel 5.3.
Here is my code
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\DB;
class ProbationCronJobEmail extends Command
{
protected $signature = 'hrm:notify';
protected $description = "";
public function __construct()
{
parent::__construct();
}
public function handle()
{
$email = 'abc#gmail.com';
\Mail::queue('emails.probation',
['empname'=>'abc','id'=>'123'],function($msg) use($email){
$msg->from('abc#gmail.com');
$msg->to($email);
$msg->subject('Probation List as on '.date('Y-M-d'));
});
}
}
abc#gmail is a dummy email, i am using my corporate email instead.
if i simple type php artisan hrm:notify, getting no error.
I have a little example. I hope this will help.
<?php
public function mails_meeting($meeting, $group, $place, $date, $message, $user)
{
$subject = "meeting " . $group;
$cargos = Cargo::where('comision_id', '=', $meeting->comision_id)->where('active', '=', '1')->get();
foreach ($cargos as $cargo) {
$mail_reciever = $cargo->asambleista->user->email;
Mail::queue('correos.comision_mail', ['group' => $group, 'place' => $place,
'date' => $date, 'message' => $message, 'user' => $user],
function ($mail) use ($subject, $mail_reciever) {
$mail->from('siarcaf#gmail.com', 'Automatic mail system');
$mail->to($mail_reciever);
$mail->subject($subject);
});
}
return 0;
}
In your_app/config/mail.php .
'sendmail' => '/usr/sbin/sendmail -bs',
'stream' => [
'ssl' => [
'allow_self_signed' => true,
'verify_peer' => false,
'verify_peer_name' => false,
],
],
.env file
MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=your_username
MAIL_PASSWORD=your_password
MAIL_ENCRYPTION=your_conf
I am trying to send emails with mailgun but they won't send and I have no idea why because i don't get any errors at all.
This is my code:
mail.php:
'driver' => env('MAIL_DRIVER', 'mailgun'),
services.php:
'mailgun' => [
'domain' => env('sandbox1e...60.mailgun.org'),
'secret' => env('key-146...419'),
],
EmailController.php:
public function send($email, $uuid = null)
{
if($uuid == null){
$uuid = User::get()->where('customer_email' , $email)->first()->email_confirmed;
}
return Mail::to($email)->send(new ConfirmEmail($uuid));
}
ConfirmEmail.php:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class ConfirmEmail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public $uuid;
public function __construct($uuid)
{
$this->uuid = $uuid;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->from('mailgun#sandbox1e17506823f2490ba9cc78cbbc2adb60.mailgun.org')
->view('emails.confirm');
}
}
I have added the emailadress I want to send to in mailgun, but it's not working. Am I doing something wrong or is there any way I can debug this?
Your configuration is wrong:
'mailgun' => [
'domain' => env('sandbox1e...60.mailgun.org'),
'secret' => env('key-146...419'),
],
The env function looks for an environment variable with the name you provide and returns the value. You should change it to the name of an environment variable and define it in your .env or don't use the env function, but that's not recommended.
Whereas Esteban Garcia's answer is correct, I to wish improve it with code snippets showing how exactly the configuration should look like:
In your config/services.php, leave the configuration as shown below:
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
],
In your .env file, that is where you define the actual mailgun credentials:
MAIL_DRIVER=mailgun
MAILGUN_DOMAIN=sandbox1e...60.mailgun.org
MAILGUN_SECRET=key-146...419
In your laravel .env configure these things
MAIL_DRIVER=mailgun
MAIL_USERNAME=postmaster#sandboxXXXXXX.mailgun.org
MAILGUN_DOMAIN=sandboxXXXXX.mailgun.org
MAILGUN_SECRET=XXXXXXX
After that goto vendor->guzzlehttp->src->client.php find
configureDefaults() method have array name called defaults that array
have verify => true change to false
'verify' => false,
then configure mail.php
'from' => ['address' => 'youremail#gmail.com', 'name' => 'yourname'],
go to route.php and test email is working or not send simple email.
plz make sure you install laravel mail class or install using this
command composer require guzzlehttp/guzzle
use Illuminate\Support\Facades\Mail;
Route::get('/', function () {
$data = [
'title'=>'title here',
'Content'=>'simple content'
];
Mail::send('email.test',$data, function ($message){
$message->to('youremail#gmail.com', 'John Smith')->subject('Welcome!');
});
});
I have created a service provider in my Laravel Application SettingsServiceProvider. This caches the settings table from the database.
$settings = $cache->remember('settings', 60, function() use ($settings)
{
return $settings->pluck('value', 'name')->all();
});
config()->set('settings', $settings);
settings table:
I am able to echo the value from the table like this:
{{ config('settings.sitename') }} //returns Awesome Images
This works fine on any blade files or controllers in App\Http\Controllers
Problem:
I am trying to echo the value to App\config\mail.php like this:
'driver' => config('settings.maildriver'),
'host' => config('settings.mailhost'),
But I'm getting this error:
Missing argument 1 for Illuminate\Support\Manager::createDriver()
Update:
I have created a new service provider MailServiceProvider to override the settings in Mail.php like this:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Config;
class MailServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
Config::set('mail.driver', config('settings.maildriver'));
Config::set('mail.host', config('settings.mailhost'));
Config::set('mail.port', config('settings.mailport'));
Config::set('mail.encryption', config('settings.mailencryption'));
Config::set('mail.username', config('settings.mailusername'));
Config::set('mail.password', config('settings.mailpassword'));
}
}
But still I am getting the same error!!
Is there any way to override default mail configuration (in app/config/mail.php) on-the-fly (e.g. configuration is stored in database) before swiftmailer transport is created?
Struggled for 3 days with this issue finally I figured out a way to solve it.
First I created a table mails and populated it with my values.
Then I created a provider MailConfigServiceProvider.php
<?php
namespace App\Providers;
use Config;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;
class MailConfigServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
if (\Schema::hasTable('mails')) {
$mail = DB::table('mails')->first();
if ($mail) //checking if table is not empty
{
$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);
}
}
}
}
And then registered it in the config\app.php
App\Providers\MailConfigServiceProvider::class,
Maybe its usefull to somebody, but I solved it as following;
In a ServiceProvider under the boot-method;
$settings = Cache::remember('settings', 60, function () {
return Setting::pluck('value', 'name')->all();
});
config()->set('settings', $settings); // optional
config()->set('mail', array_merge(config('mail'), [
'driver' => 'mailgun',
'from' => [
'address' => $settings['mail_from_address'],
'name' => $settings['mail_from_name']
]
]));
config()->set('services', array_merge(config('services'), [
'mailgun' => [
'domain' => $settings['mailgun_domain'],
'secret' => $settings['mailgun_secret']
]
]));
I used array_merge with the original config, so we only override the values we need to. Also we can use the Cache-facade in the boot-method.
Following the instructions here is the proper solution to the problem, in case if you're sending multiple emails per request over different SMTP configurations, Config::set() won't work right, the first email will use the correct settings, while all upcoming emails within the same request will use the same configuration of the first one, because the Mail service is provided as a singleton thus only the initial configurations will be used.
This also might affect emails sent over Laravel queue workers due to the same reason.
After research a lot, finally I found the best possible way to dynamic mail configuration.
I am saving my mail configuration data in the settings table, please have a look at the table structure.
Helpers/AaapHelper.php
<?php
namespace App\Helpers;
use App\Setting;
class AppHelper
{
public static function setMailConfig(){
//Get the data from settings table
$settings = Setting::pluck('description', 'label');
//Set the data in an array variable from settings table
$mailConfig = [
'transport' => 'smtp',
'host' => $settings['smtp_host'],
'port' => $settings['smtp_port'],
'encryption' => $settings['smtp_security'],
'username' => $settings['smtp_username'],
'password' => $settings['smtp_password'],
'timeout' => null
];
//To set configuration values at runtime, pass an array to the config helper
config(['mail.mailers.smtp' => $mailConfig]);
}
}
app\Http\Controllers\SettingController.php
<?php
namespace App\Http\Controllers;
use App\Helpers\AppHelper;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
class SettingController extends Controller
{
public function sendMail()
{
try
{
//Set mail configuration
AppHelper::setMailConfig();
$data = ['name' => "Virat Gandhi"];
Mail::send(['text' => 'mail'], $data, function ($message)
{
$message->to('abc#gmail.com', 'Lorem Ipsum')
->subject('Laravel Basic Testing Mail');
$message->from('xyz#gmail.com', $data['name']);
});
return redirect()->back()->with('success', 'Test email sent successfully');
}
catch(\Exception $e)
{
return redirect()->back()->withErrors($e->getMessage());
}
}
}
Explanation
While sending a mail through the sendMail function it will first configure mail through helper.
I'd like to keep users away from editing configuration files, so I've made web interface in admin panel for setting up Mail server, username, password, port, encryption..
I was working well in Laravel 4.2, but now when the app has been rewritten into Laravel 5, an error occurs:
Class 'Settings' not found in <b>F:\htdocs\app\config\mail.php</b> on line <b>18</b><br />
For this purpose I've created a service provider, made a facade, put them in config/app.php, Settings::get('var')/Settings::set('var') work perfectly, but not for mail settings.
config/mail.php:
<?php return array(
'driver' => Settings::get('mail_driver'),
'host' => Settings::get('mail_host'),
'port' => Settings::get('mail_port'),
'from' => array('address' => Settings::get('mail_from_address'), 'name' => Settings::get('mail_from_name')),
'encryption' => Settings::get('mail_encryption'),
'username' => Settings::get('mail_username'),
'password' => Settings::get('mail_password'),
'sendmail' => Settings::get('mail_sendmail'),
'pretend' => false,
);
config/app.php:
'providers' => [
...
'App\Providers\SettingsServiceProvider',
...
'aliases' => [
...
'Settings' => 'App\Custom\Facades\Settings',
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Custom\Settings;
class SettingsServiceProvider extends ServiceProvider {
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->singleton('settings', function()
{
return new Settings;
});
}
}
<?php namespace App\Custom;
use App\Setting;
class Settings {
public function get($var) {
try{
$setting = Setting::first();
} catch(exception $e)
{
return false;
}
return $setting->$var;
}
public function set($var, $val) {
try{
$setting = Setting::first();
$setting->$var = $val;
$setting->save();
} catch(exception $e)
{
return false;
}
return true;
}
}
<?php
namespace App\Custom\Facades;
use Illuminate\Support\Facades\Facade;
class Settings extends Facade {
protected static function getFacadeAccessor() { return 'settings'; }
}
Any ideas how to implement Laravel mail settings using database?
To archive this I created CustomMailServiceProvider by extending Illuminate\Mail\MailServiceProvider so as to overwrite this method:
protected function registerSwiftTransport(){
$this->app['swift.transport'] = $this->app->share(function($app)
{
return new TransportManager($app);
});
}
Here is the complete solution
I created CustomMailServiceProvider.php in app\Providers
namespace App\Providers;
use Illuminate\Mail\MailServiceProvider;
use App\Customs\CustomTransportManager;
class CustomMailServiceProvider extends MailServiceProvider{
protected function registerSwiftTransport(){
$this->app['swift.transport'] = $this->app->share(function($app)
{
return new CustomTransportManager($app);
});
}
}
I created CustomTransportManager.php in app/customs directory -
NB: app/customs directory doesn't exist in default laravel 5 directory structure, I created it
namespace App\Customs;
use Illuminate\Mail\TransportManager;
use App\Models\Setting; //my models are located in app\models
class CustomTransportManager extends TransportManager {
/**
* Create a new manager instance.
*
* #param \Illuminate\Foundation\Application $app
* #return void
*/
public function __construct($app)
{
$this->app = $app;
if( $settings = Setting::all() ){
$this->app['config']['mail'] = [
'driver' => $settings->mail_driver,
'host' => $settings->mail_host,
'port' => $settings->mail_port,
'from' => [
'address' => $settings->mail_from_address,
'name' => $settings->mail_from_name
],
'encryption' => $settings->mail_encryption,
'username' => $settings->mail_username,
'password' => $settings->mail_password,
'sendmail' => $settings->mail_sendmail,
'pretend' => $settings->mail_pretend
];
}
}
}
And finally, I replaced 'Illuminate\Mail\MailServiceProvider', in config/app.php with 'App\Providers\CustomMailServiceProvider',
I have added
$this->app['config']['services'] = [
'mailgun' => [
'domain' => $settings->mailgun_domain,
'secret' => $settings->mailgun_secret,
]
];
to CustomTransportManager __construct() to include mailgun API credentials that I'm using as mailing service
I configured as mentioned, however got the following error. While I tried your code found that from Laravel 5.4 share method is deprecated and instead informed to use singleton.
Call to undefined method Illuminate\Foundation\Application::share()
here is the below method using singleton instead using share method:
protected function registerSwiftTransport(){
$this->app->singleton('swift.transport', function ($app){
return new CustomTransportManager($app);
});
}
#DigitLimit , method share() has been dropped since Laravel 5.4. I had to work-around this problem using other methods, and I am not sure they are perfect. Here is my registerSwiftTransport() method in CustomMailServiceProvider class.
Firstly, we need to determine if code is not executed while calling app through command line: "if(strpos(php_sapi_name(), 'cli') === false)". If we don't check that and don't prevent setting new params in this case, Artisan will throw us errors in command line. Secondly, we need to get settings from database somehow. I did it using my method getSettingValue(), where first argument is setting key, and second argument is default value if setting is not found. As you see, I assigned settings to $this->app['config']['mail'].
After that, I used singleton() method:
protected function registerSwiftTransport(){
if (strpos(php_sapi_name(), 'cli') === false) {
$this->app['config']['mail'] = [
'driver' => Setting::getSettingValue('mail_driver', '****'),
'host' => Setting::getSettingValue('mail_host', '****'),
'port' => Setting::getSettingValue('mail_port', 25),
'from' => [
'address' => Setting::getSettingValue('mail_from_address', '****'),
'name' => Setting::getSettingValue('mail_from_name', '****'),
],
'encryption' => Setting::getSettingValue('mail_encryption', '***'),
'username' => Setting::getSettingValue('mail_username', '****'),
'password' => Setting::getSettingValue('mail_password', '****'),
];
}
$this->app->singleton('swift.transport', function ($app) {
return new Illuminate\Mail\TransportManager($app);
});
}