Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi key and domain #38

Open
fyher opened this issue Mar 28, 2017 · 16 comments
Open

Multi key and domain #38

fyher opened this issue Mar 28, 2017 · 16 comments

Comments

@fyher
Copy link

fyher commented Mar 28, 2017

How I can use , if I want multi domain and key ?

thanks

@Nyholm
Copy link
Collaborator

Nyholm commented Mar 29, 2017

I do not think that is supported. That should be an excellent feature.

@fyher
Copy link
Author

fyher commented Mar 29, 2017

it 's possible to move the api key to the file config in param in the mailer class ?

@Nyholm
Copy link
Collaborator

Nyholm commented Mar 30, 2017

I'm not too sure what you mean.

I think we should allow config like:

Mailgun:
  foo:
    Key: xx
    Domain: xx
  Bar:
    Key: yay
    Domain: yay

@fyher
Copy link
Author

fyher commented Mar 31, 2017

why not.But this don't working actually ?

@Nyholm Nyholm modified the milestone: Release 0.4 Apr 14, 2017
@stevechilds
Copy link

Can't believe this hasn't been implemented, this is actually a show stopper for us. Our CRM platform hosts multiple sites from the same setup, we need the ability to support multiple domains.

sigh time to have a dig around in the code.

@tehplague
Copy link
Owner

Mailgun itself does in fact support multiple domains per account. If they are managed in the same account it should perfectly be possible to use them.

@stevechilds
Copy link

stevechilds commented Apr 8, 2018

Actually, there's a very simple solution - subclass the Transport class! Symfony allows you to specify any service as a transport in the config, doing this allows you to inject other dependencies into the transport constructor, allowing you to change the domain passed through to the underlying Mailgun Transport.

If anyone is interested...

Step 1, create a custom class (customMailgunTransport.php) - I saved this into src/BundleName/SwiftMailer

<?php

namespace foo\WebsiteBundle\SwiftMailer;

use cspoo\Swiftmailer\MailgunBundle\Service\MailgunTransport;
use Mailgun\Mailgun;
use Symfony\Component\DependencyInjection\ContainerInterface;


class customMailgunTransport extends MailgunTransport
{
    public function __construct(ContainerInterface $container, \Swift_Events_EventDispatcher $eventDispatcher, Mailgun $mailgun, $domain)
    {
        parent::__construct($eventDispatcher, $mailgun, $domain);

    }
}

Then create the new service entry in services.yml...

    # Custom SwiftMailer Mailgun Transport - gets credentials from site config.
    swiftmailer.mailer.transport.custom_mailgun:
              class: foo\WebsiteBundle\SwiftMailer\customMailgunTransport
              arguments: [@service_container,'@mailgun.swift_transport.eventdispatcher','@mailgun.library','mydomain.com']

Alter the mail config - in our case we want the mailgun transport to be manually selected in the code...
(in config_global.yml) - I can't recall if this is a stock Symfony file or not, it may just be config.yml

swiftmailer:
    default_mailer: default
    mailers:
        default:
            transport: %mailer_transport%
            host:      %mailer_host%
            username:  %mailer_user%
            password:  %mailer_password%
        mailgun:
            transport: custom_mailgun

Then when you want to send via mailgun, you create it with a call like:

$swiftmailer = $this->getContainer()->get('swiftmailer.mailer.mailgun');

The service name is swiftmailer.mailer. and then the mailer name from the config.yml file.

HTH....

@fyher
Copy link
Author

fyher commented Apr 9, 2018

it' no possible to override the getConfigTreeBuilder with the information in the DB table ?
i have all information for my site in my CRM in database and it's possible to send this to mailgun ?

@Nyholm
Copy link
Collaborator

Nyholm commented Apr 9, 2018

You cannot (or should not) access your database at the time when you build your container. That means you have to redeploy every time you get a new customer.

What you should do is to create a factory that spits out a new instance of the client each time you call it. That factory itself should check with your database values.

@fyher
Copy link
Author

fyher commented Apr 9, 2018

it's no possible to override cspooSwiftmailerMailgunExtension ? and inject in the val with my database ?

@stevechilds
Copy link

@fyher - If you take the approach I posted above, you can do what you want to do. You'd load the config in the constructor of the customMailgunTransport class.

@stevechilds
Copy link

  • Its what we do, except we load the config from YML files which in turn are cached in Redis. It saves a trip to the DB on every page load (or in this case, whenever the service is created)

@fyher
Copy link
Author

fyher commented Apr 9, 2018

hi i have success :)
create the override for te transport

`<?php

namespace AdminBundle\SwiftMailer;

use cspoo\Swiftmailer\MailgunBundle\Service\MailgunTransport;
use Mailgun\Mailgun;
use Symfony\Component\DependencyInjection\ContainerInterface;

class CustomMailgunTransport extends MailgunTransport
{

private $mailgun;
private $event;

public function __construct(ContainerInterface $container, \Swift_Events_EventDispatcher $eventDispatcher, Mailgun $mailgun)
{


   $this->mailgun=$mailgun;
   $this->event=$eventDispatcher;

}

public function choiceDomaine($domain){

    parent::__construct($this->event, $this->mailgun, $domain);

}

}`
in file config:

cspoo_swiftmailer_mailgun: key: "key" domain: "domaineA"

the service
custom_mailgun: class: AdminBundle\SwiftMailer\CustomMailgunTransport arguments: ['@service_container','@mailgun.swift_transport.eventdispatcher','@mailgun.library']

and in the controller for example:

`$m=$this->get("swiftmailer.mailer");
$mails=$this->get("custom_mailgun")->choiceDomaine("domaineB.com");

    $mail = \Swift_Message::newInstance();
    $mail -> setFrom("[email protected]", "text")
        -> setTo("[email protected]")
        -> setSubject("text")
        -> setBody("it's me ")
        -> setContentType("text/html");


    $m->send($mail);`

in the log of mailgun, I have the email send with domaine B , you can change domaineC etc.. it's work

@stevechilds
Copy link

public function choiceDomaine($domain){

    parent::__construct($this->event, $this->mailgun, $domain);

}

Whilst it may work, I'd refactor this so you're not calling the parent's constructor method, perhaps move that functionality into a method called 'init' or something. But glad to see it worked out :) 👍

@stevechilds
Copy link

stevechilds commented Apr 12, 2018

Actually, there's another way to do this without subclassing the Transport class. When the transport sends the message it checks the headers of the email to see if there is a mailgun domain tag there, if there is it uses it.

So, either set the header each time you create a message, or better still, use a SwiftPlugin to do it for you.

Services.yml:

    swiftmailer.mgDomainSetter:
        class:        path\toYourBundle\SwiftMailer\Plugins\domainSetterPlugin
        tags:
          - { name: swiftmailer.default.plugin }
          - { name: swiftmailer.mailgun.plugin }

Note, you'll probably only need one tag, for the default, but we're using mailgun along side other transports, so you need to specify which mailers to attach the plugin to.

domainSetterPlugin.php

<?php

namespace path\toYourBundle\SwiftMailer\Plugins;
use Monolog\Logger;


class domainSetterPlugin implements \Swift_Events_SendListener
{
    /**
     * Invoked immediately before the Message is sent.
     *
     * @param \Swift_Events_SendEvent $evt
     */
    public function beforeSendPerformed(\Swift_Events_SendEvent $evt)
    {
        $msg = $evt->getMessage();
        // Ok, is it being sent via mailgun, if so, we need to set the domain to the sender's domain.
        // all our domains are on the prefix of mg., so we need to prefix this with the sender's email domain.
        if ($evt->getSource() instanceof MailgunTransport) {
           $sender = $msg->getFrom();
           if (array($sender)) {
               // The array is email_address => name, so we need to get the domain name.
               $sender = implode('',array_keys($sender));

               // Firstly, set the sender param of the mail, this stops Mailgun mangling the sender and firing off spam traps!
               // e.g. the sender ends up being set to Sender: [email protected] in the email message.
               $msg->getHeaders()->addTextHeader('sender',$sender);
               $domain = 'mg.' . substr($sender,strpos($sender,'@')+1);
               $msg->getHeaders()->addTextHeader('mg:domain',$domain);
           }
        }
    }
}

And that should be it! It does rely on your senders being from domains you've got setup in mailgun however, so if this is not the case, this won't work for you as you'll get invalid domains. Hopefully it may help you either as-is or as inspiration!

@petermanser
Copy link

I prefer to set it dynamically for every message like this:

<?php

use cspoo\Swiftmailer\MailgunBundle\Service\MailgunTransport;

class MyMailer {
    //...

    public function sendMessage(string $mailFrom)
    {
        $message = \Swift_Message::newInstance();
            ->setSubject('foo')
            ->setBody('bar')
            ->setFrom($mailFrom);

        $domain = $this->getDomain();
        if ($domain) {
            $message->getHeaders()->addTextHeader(MailgunTransport::DOMAIN_HEADER, $domain);
        }

        // send message
    }

    //...

    public function getDomain(string $mailFrom): ?string
    {
        $split = explode('@', $this->mailFrom);
        if (isset($split[1])) {
            return $split[1];
        }

        return null;
    }
}

Hope that helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants