Using mandrill as a mail transport layer in Zend 1 - php

Currently, I am trying to integrate Mandrill functionality into a Zend 1 legacy application, and I'm not too familiar with the way they handle mail transports. Currently, I'm including the mandrill/mandrill composer package and attempting to follow the pattern of the other transport layers included in Zend 1:
class MandrillTransport extends Zend_Mail_Transport_Abstract
{
private $message = array();
protected function _formatMandrillArray()
{
//grab all the relavant data from the pre-existing mail object and put it into a Mandrill-friendly array
}
protected function _getAttachments() {
//loop through and format attachments that get added to array
}
protected function _sendMail()
{
//send Mandrill message with included data
$mandrill = new Mandrill(Zend::registry('config')->mandrill->APIKey);
$mandrill->messages->send($this->message);
}
public function send() {
//Format all the stuff and send it
}
}
And then I'm assuming I can use this in the "send()" function, which appears to take the transport as a parameter:
//TODO: Put this in a better spot
require_once __DIR__ . "/ZendFramework/Zend/Mail/Transport/MandrillTransport.php";
$tr = new MandrillTransport();
$email->send($tr);
Am I on the right track here? The reason I'd like to do this as a transport layer rather than just ripping out the existing code and replacing it with Mandrill is because there are a lot of different business processes sending mail, and we'd like to be able to pick and choose which is using the Sendmail transport and which are using Mandrill.
Thanks in advance,
-Chris

Related

Pass variables to custom mail transport in laravel

Laravel provides the possibility to implement your own mail transport in order to send email over APIs that they aren't implemented in the framework itself by extending Illuminate\Mail\Transport\Transport. I have done so for the gmail API as this provides some benefits over sending over SMTP. There is however a scenario which is giving me some difficulties: the API requires you to impersonate a given user to send mail as that user. Currently, I'm using the 'from' address to perform that action.
use Illuminate\Mail\Transport\Transport;
use Google\Client as GoogleClient;
class MailTransport extends Transport
{
public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
{
$client = new GoogleClient;
// initialise the client further, code omitted
$client->setSubject(
array_key_exists(0, array_keys($message->getFrom()))
? array_keys($message->getFrom())[0]
: self::DEFAULT_SUBJECT
);
// send the email here using the impersonated $client
}
}
This works fine, however I'm running into an issue when I want to send a mail from a mail alias of that user. In that case, the from address doesn't match the google account to impersonate and sending the mail doesn't work. I'm looking for a way to pass the google account to impersonate to the Mailtransport. As an instance of this class is automatically created by the framework and only Swift_Mime_SimpleMessage can be used, my best solution right now is to add a custom header to the email which is read and then removed by the MailTransport class. This feels like a dirty workaround however, does anybody know a cleaner solution?

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

How to also send BCC to specific address during development with Symfony Mailer?

Symfony provides a way to send all emails to a specific email address during debugging and development but addressees in the BCC still receive the e-mail. This is very dangerous because you don't want to send out any emails from your local dev environment.
Is there a way to also deliver BCCs to a specific email address?
I wouldn't discount having your own wrapper service for Mailer. I have to admit I usually do that, since more often than not I consider the sending of emails too close to the application concerns, and I may want more freedom and flexibility than simply coupling myself to the frameworks package, as good as it may be.
That being said, Symfony's method of changing the recipients does not work with Bcc, because Bcc is part of the message, while the listener that changes the recipients manipulates the envelope.
You could create your own EventListener to manipulate the bcc header:
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Mailer\Event\MessageEvent;
use Symfony\Component\Mime\Message;
class ManipulateBcc implements EventSubscriberInterface
{
private bool $removeExisting;
private array $forcedBcc;
public function __construct(bool $removeExisting = false, array $forcedBcc = [])
{
$this->removeExisting = $removeExisting;
$this->forcedBcc = $forcedBcc;
}
public static function getSubscribedEvents(): array
{
return [
MessageEvent::class => ['onMessage', -224],
];
}
public function onMessage(MessageEvent $event): void
{
if ( ! $this->removeExisting) {
return;
}
$message = $event->getMessage();
if ( ! $message instanceof Message) {
return;
}
$headers = $message->getHeaders();
if ($headers->has('bcc')) {
$headers->remove('bcc');
}
if ( ! empty($this->forcedBcc)) {
$headers->addMailboxListHeader('bcc', $this->forcedBcc);
}
}
}
By default, this does nothing. With the default configuration the eventlistener will be run but since removeExisting will be false, the listener will return without doing anything.
To enable it, you could add the following to services_dev.yaml, so it's only enabled during development:
# config/services_dev.yaml
services:
App\EventDispatcher\ManipulateBcc:
autoconfigure: true
arguments:
$removeExisting: true
$forcedBcc:
- 'fake.email#mailinator.com'
- 'even.faker#mailinator.com'
This was hastily written, and you cannot force BCCs without removing BCCs, which may be sufficient for many purposes but maybe not to your own. Use this as a starting point until it does what you need.
The only way which I think of right now is to create your own wrapper service for the mailer and check the environment if it’s dev just remove the BCC... you don’t need them anyway.

Laravel pretend is not showing cc mail address

I had change pretend as true in mail config. please check http://laravel.com/docs/4.2/mail#mail-and-local-development
Now log is showing to address like this.
[2014-11-22 17:12:49] production.INFO: Pretending to mail message to: dinukathilanga#gmail.com, bbelekkaya#gmail.com [] []
But i need debug cc emails also. How can i do it?
This is my code.
Mail::send($view, $data, function($message) use ($to, $cc, $subject)
{
foreach ($to as $toUser) {
$message->to($toUser['email'], $toUser['first_name'] . ' ' . $toUser['last_name']);
}
foreach ($cc as $ccUser) {
$message->cc($ccUser['email'], $ccUser['first_name'] . ' ' . $ccUser['last_name']);
}
$message->subject($subject);
});
Allow me to be frank here. I am new to Laravel, but I will try my best to explain this.
I do know how to debug email platforms though, the easiest process is by doing it through C.
I will try to be succint as possible.
Firstly, try using the laravel-debugbar (the latest version is 4).
This is an application that is capable of filtering the PHP Debug Bar.
By using this application you will be able to attach and edit output functions (here is the link for more information: Debug bar.
If this won't work, try debugging through C.
Fristly, you will compile the C program by inserting the debug option, option -g.
Afterwards, you'll launch the gdb into the platform.
Thirdly, you'll break the point in the C program, specifically, insert the break line_number function.
After that, you'll print the variable values in the gdp debugger.
For instance, you'll type commands such as print j and (gdp) p i (I will post the website where I've got this information from; it will give you a more broader walkthrough).
There are various operation for this process.
I strongly advise you visiting:Debug C program using gdb. Hope this helped.
Create a new class named ExtendedMailer for the sake of this example and save the file somewhere the autoloader is able to find it. Depending on where you put the file, you may need to run composer dump-autoload once you've saved it.
<?php
use Illuminate\Mail\Mailer;
class ExtendedMailer extends Mailer
{
protected function logMessage($message)
{
parent::logMessage($message);
$emails = implode(', ', array_keys((array) $message->getCc()));
$this->logger->info("Pretending to mail message to: {$emails}");
}
}
Create a new service provider, somewhere your application is able to load classes. As above, you may need to run composer dump-autoload
The below code simply extends the original MailServiceProvider but allows us to bind a different class to in the IoC, you'll notice the new ExtendedMailer; the class we created earlier. Obviously if you namespaced the class, reflect that change here.
<?php
use Illuminate\Mail\MailServiceProvider;
class ExtendedMailServiceProvider extends MailServiceProvider
{
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$me = $this;
$this->app->bindShared('mailer', function($app) use ($me)
{
$me->registerSwiftMailer();
// Once we have create the mailer instance, we will set a container instance
// on the mailer. This allows us to resolve mailer classes via containers
// for maximum testability on said classes instead of passing Closures.
$mailer = new ExtendedMailer(
$app['view'], $app['swift.mailer'], $app['events']
);
$this->setMailerDependencies($mailer, $app);
// If a "from" address is set, we will set it on the mailer so that all mail
// messages sent by the applications will utilize the same "from" address
// on each one, which makes the developer's life a lot more convenient.
$from = $app['config']['mail.from'];
if (is_array($from) && isset($from['address']))
{
$mailer->alwaysFrom($from['address'], $from['name']);
}
// Here we will determine if the mailer should be in "pretend" mode for this
// environment, which will simply write out e-mail to the logs instead of
// sending it over the web, which is useful for local dev environments.
$pretend = $app['config']->get('mail.pretend', false);
$mailer->pretend($pretend);
return $mailer;
});
}
}
In your config/app.php, you'll find a line which looks like
'Illuminate\Mail\MailServiceProvider',
You'll need to comment it out and add a line as below
'ExtendedMailServiceProvider',
What this does is replace the mailer which Laravel knows about with the one you've just created. The one you've just created is the same as the default one as it merely extends it, and adds functionality to the logMessage function.

PHP Codeigniter: Is there an elegant way to to get the SMTP return code upon a mail failure

When using the standard Codeigniter
mail->send()
it only returns TRUE or FALSE. However, I have requirements to handle certain SMTP return codes differently. I could parse out of the debug text info, or somehow try to override the mail handler for Codeigniter. Is there any straight forward and elegant way to do this?
Thanks in advance.
I dont think there is a build in mechanism for this in CodeIgniter. What you could do is extend the CI email class and add a function to expose the protected _debug_msg array.
If you look at the source of email class you will see that print_debugger() function is converting _debug_msg array into string. So if _debug_msg has what you are looking for then you wouldn't have to parse any string.
class MY_Email extends CI_Email {
public function __construct()
{
parent::__construct();
}
public get_msg()
{
if (count($this->_debug_msg) > 0)
{
return $this->_debug_msg;
}
else
{
return FALSE;
}
}
}
Refer the following link on how to extend CI libs
http://codeigniter.com/user_guide/general/creating_libraries.html
If you're sending emails using sendmail you may not be able to get the SMTP return codes until later.
The way to get bounces (I'm guessing?) is by adding a Return-Path to your outgoing emails and choose an email inbox that's manned by procmail, so that you can pipe the feedback emails back into PHP to parse it.
Let me know if you need more details on the above.

Categories