Symfony Mailer trouble - php

The code does not work(. It gives me the error
<?php
error_reporting(E_ALL);
ini_set('display_errors', 'On');
require_once 'vendor/autoload.php';
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mime\Email;
$transport = Transport::fromDsn('smtp://mymail#gmail.com:MYPASS#smtp.gmail.com:587');
$mailer = new Mailer($transport);
$email = (new Email());
$email->from('mymail#gmail.com');
$email->to('mymail#gmail.com');
$email->subject('Some subject');
$email->text('test-message');
$mailer->send($email);
?>
Tried to 'require' files with these classes, but it did not help. Also I checked my composer.json. There was Symfony, so I`m sure, I have it installed with my composer.

The issue with the code is that the DSN (Data Source Name) specified for the Transport object is incorrect.
The correct DSN for Gmail should be
smtp://mymail%40gmail.com:MYPASS#smtp.gmail.com:587
(the email address in the username part of the DSN should be URL encoded). Additionally, it's not recommended to hard-code the password in the code as it can pose a security risk. Instead, the password should be stored in a secure environment variable.

Related

How can i send Mails within my Typo3 extension

I get results from a jQuery Survey in JSON within my Typo3 Extension. Now I want to send these results with the Typo3 Mail API to my Inbox. According to the documentations following shoud do the work
$mail = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Mail\MailMessage::class);
$mail->from(new \Symfony\Component\Mime\Address('john.doe#example.org', 'John Doe'));
$mail->to(
new \Symfony\Component\Mime\Address('receiver#example.com', 'Max Mustermann'),
new \Symfony\Component\Mime\Address('other#example.net')
);
$mail->subject('Your subject');
$mail->text('Here is the message itself');
$mail->html('<p>Here is the message itself</p>');
$mail->attachFromPath('/path/to/my-document.pdf');
$mail->send();
so my code looks like this:
namespace TYPO3\CMS\Core\Mail;
if (!file_exists( dirname(__DIR__, 2).'/vendor/autoload.php' )) {
throw new \RuntimeException(
'Could not find vendor/autoload.php, make sure you ran composer.'
);
} else {
require dirname(__DIR__, 2).'/vendor/autoload.php';
}
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\MailUtility;
$mail = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Mail\MailMessage::class);
$mail->from(new \Symfony\Component\Mime\Address('john.doe#example.org', 'John Doe'));
$mail->to(
new \Symfony\Component\Mime\Address('receiver#example.com', 'Max Mustermann'),
new \Symfony\Component\Mime\Address('other#example.net')
);
$mail->subject('Your subject');
$mail->text('Here is the message itself');
$mail->html('<p>Here is the message itself</p>');
$mail->attachFromPath('/path/to/my-document.pdf');
$mail->send();
I just getting errors. Does anyone know how i can achieve this?
Following error i get
Notice: Undefined index: TYPO3_CONF_VARS in /var/www/html/local_packages/ext_sitepackage/public/typo3/sysext/core/Classes/Mail/Mailer.php on line 170
Apparently this is the same question as you already posted here.
This will never work like this. You need to either build a fully fledged TYPO3 extension or a standalone application using symfony/mailer directly.
Your script is missing $GLOBALS['TYPO3_CONF_VARS']['MAIL'].
You stumble over the fact that you're programming past the conventions and requirements of TYPO3, but then you're surprised that the framework's functions don't work...
Create a middleware in your sitepackage, and register it correctly. Check for a special route and let the rest run. If handling, use the code there.
You need to run the mailing code in a (full) bootstrapped Typo3 context:
in a middleware
extbase plugin registered with pageNum directly
Your pasted code looks weired in a lot of ways. Just putting a file in a extension folder do not mean that is correctly a typo3 extension.
Maybe you want to start and have a proper extension setup first, with the corresponding readings:
ext_emconf.php / composer.json as a minimum
code files in 'Classes/' subfolders
then decide with which way you want to handle the "ajax" call and send the email, there are several possibilities (as already mentioned above) .. than read and implement that solution the proper and correct way.
Just having a php file directly referenced/called and just bootstpping the composer autoloader do not and never will be bootstrapping Typo3 with all needed configuration bootstrapping (gathering confings from extensions, Local/AdditionalConfiguration, siteconfig and and and).
And generally a package/extension should have a namespace something like following (as a convention):
<extensionname.....
an thus registered as psr-4 autoloading in your extension composer.json ..
Starting to implement the peaces to simulate a Typo3 bootstpraping in that file is not good and will make a lot of headache ... it's easier to have a proper sitepacke/extension structure.

Use the symfony/mailer component without the symfony framework

I am working on a project that doesn't use any framework and I would like to use Symfony Mailer component to handle sending emails.
The installation part (composer require) was well handled and everything is included in my code without any error. However, I still have a problem : the documentation of the component seems to be written only for using it with the symfony framework.
Indeed, it is refering to autoloaded config files that o
bviously don't exist in my app.
This implementation seems to be very tricky and I was wondering if any of you guys already faced the same problem and what solution you came up with?
Your question made me wonder too how it is easy to send mail only with the mailer component.
So I created a new project from scratch and tried the simplest possible version following the mailer component documentation.
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mime\Email;
class MyMailer
{
// googleDns format is gmail+smtp://USERNAME:PASSWORD#default
public function __construct(private string $googleDsn)
{
}
public function send()
{
$template = file_get_contents('https://raw.githubusercontent.com/leemunroe/responsive-html-email-template/master/email.html');
$transport = Transport::fromDsn($this->googleDsn);
$mailer = new Mailer($transport);
$email = (new Email())
->from('mygmail#address.com')
->to('thedelivery#gmail.com')
->subject('Time for Symfony Mailer!')
->html($template);
$mailer->send($email);
}
}
And I successfully received my mail. I send my mail with gmail, for your information. Transport class should do the sending job for you, but if not you can have a look to inside vendor/symfony/mailer/Transport folder

PHP getenv always returns false

The getenv() always returns false. I am using Symfony dotenv library and loading my variables from a .env file in the root of my project.
use Symfony\Component\Dotenv\Dotenv;
use Symfony\Component\Dotenv\Exception\PathException;
if (!getenv('APP_ENV')) {
try {
(new Dotenv())->load(__DIR__ . '/../.env');
} catch (PathException $ex) {
echo $ex->getMessage();
exit(1);
}
}
var_dump(getenv('APP_ENV')); // bool(false)
But when I dump the super global I can see my variables
var_dump($_ENV); // array:1["APP_ENV" => "dev"]
So what am I missing?
I m not using symfony but i've encountered the some problem
i am using the vlucas library this is my first code that caused the problem
define('BASE_PATH',realpath(__DIR__.'/../../'));
require_once __DIR__.'/../../vendor/autoload.php';
$dotEnv = Dotenv\Dotenv::createImmutable(BASE_PATH);
$dotEnv->load();
$appName=$_ENV['APP_NAME'];
$appName2=getenv('APP_NAME');
var_dump($appName) // return "This is my website";
var_dump($appName2) // return false;
i didn't knwo the problem at first but it seems that it was because putenv() and getenv()
are not thread safe
so i changed it to this code
define('BASE_PATH',realpath(__DIR__.'/../../'));
require_once __DIR__.'/../../vendor/autoload.php';
$dotEnv = Dotenv\Dotenv::createUnsafeImmutable(BASE_PATH);// <======== :) look here
$dotEnv->load();
$appName=$_ENV['APP_NAME'];
$appName2=getenv('APP_NAME');
var_dump($appName) // return "This is my website";
var_dump($appName2) // return "This is my website";
i hope this resolves your issue
For Symfony 5.x+, in public/index.php
replace
(new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
with
(new Dotenv())->usePutenv()->bootEnv(dirname(__DIR__).'/.env');
This worked for me.
By default, Symfony doesn't use putenv() (I think it's for security reasons, don't remember exactly) so you are not able to use directly getenv() if you are using Symfony's "fake" environment variables.
The best solution in my opinion is to use dependency injection instead. You can access env vars in your Symfony configuration. For example with a yaml configuration file:
framework:
secret: '%env(APP_SECRET)%'
If you want to be able to use getenv() anyway, that I don't recommand for multiple reasons, you can do this :
Before Symfony 5.1 : In your config/bootstrap.php file -> new Dotenv(true)
Symfony 5.1 and later : public/index.php, add the following before Dotenv instantation-> Dotenv::usePutenv();
EDIT :
Using the putenv PHP function is not thread safe, that's why this setting defaults to false.
Didn't notice in the first place your using the Dotenv component as a standalone library, so you can ignore my advice concerning the dependency injection.
The reason is that using getenv() and putenv() is strongly discouraged due to the fact that these functions are not thread safe, however it is still possible to instruct PHP dotenv to use these functions. Instead of calling Dotenv::createImmutable, one can call Dotenv::createUnsafeImmutable, which will add the PutenvAdapter behind the scenes. Your environment variables will now be available using the getenv method, as well as the super-globals:
$s3_bucket = getenv('S3_BUCKET');
$s3_bucket = $_ENV['S3_BUCKET'];
$s3_bucket = $_SERVER['S3_BUCKET'];

How to send a mail with PHPMailer from Monolog when an error occurs

I'm using Monolog (https://github.com/Seldaek/monolog) in my project and we want to receive an email when there are errors in our application. The logs are working as expected but if the log level is ERROR (below log level is DEBUG), I want the logger to send me an email.
I tried to use the class NativeMailHandler but it doesn't seems to work and I would prefer to use our SMTP mail server (works great in PHP but I can't figure out how to link it with Monolog error handler)
$logger = new Logger('LOG');
$logHandler = new StreamHandler('synchro.log',Logger::DEBUG);
$logger->pushHandler($logHandler);
I created PHPMailer handler for Monolog. It enables you to send logs to emails with PHPMailer.
It is available on GitHub and Packagist, but it can also be used without Composer (which requires manual installation of Monolog and PHPMailer).
<?php
use MonologPHPMailer\PHPMailerHandler;
use Monolog\Formatter\HtmlFormatter;
use Monolog\Logger;
use Monolog\Processor\IntrospectionProcessor;
use Monolog\Processor\MemoryUsageProcessor;
use Monolog\Processor\WebProcessor;
use PHPMailer\PHPMailer\PHPMailer;
require __DIR__ . '/vendor/autoload.php';
$mailer = new PHPMailer(true);
$logger = new Logger('logger');
$mailer->isSMTP();
$mailer->Host = 'smtp.example.com';
$mailer->SMTPAuth = true;
$mailer->Username = 'server#example.com';
$mailer->Password = 'password';
$mailer->setFrom('server#example.com', 'Logging Server');
$mailer->addAddress('user#example.com', 'Your Name');
$logger->pushProcessor(new IntrospectionProcessor);
$logger->pushProcessor(new MemoryUsageProcessor);
$logger->pushProcessor(new WebProcessor);
$handler = new PHPMailerHandler($mailer);
$handler->setFormatter(new HtmlFormatter);
$logger->pushHandler($handler);
$logger->error('Error!');
$logger->alert('Something went wrong!');
Well, I found a solution to my problem, maybe it will help someone one day:
Since the class NativeMailHandler is using the mail() php function. I changed the code in monolog/monolog/src/Monolog/Handler/NativeMailhandler.php of the function send() and I declared my PHPMailer() there instead of the mail() function.
$mailHandler = new NativeMailerHandler(your_email#email.com, $subject, $from,Logger::ERROR,true, 70);
$logHandler = new StreamHandler('synchro.log',Logger::DEBUG);
$logger->pushHandler($logHandler);
$logger->pushHandler($mailHandler); //push the mail Handler. on the log level defined (Logger::ERROR in this example), it will send an email to the configured mail in the send() function in monolog/monolog/src/Monolog/Handler/NativeMailhandler.php

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.

Categories