Symfony 3.3 and Swiftmailer - mail created and sent by controller deferred by server
Asked Answered
B

3

22

I'm trying to use Swiftmailer to send emails out from a website. The emails keep getting deferred because Swiftmailer is attempting to use my server's IP address rather than localhost as the relay:

Aug  2 14:18:28 picus sm-mta[21171]: v72IIS0I021171: from=<[email protected]>, size=347, class=0, nrcpts=1, msgid=<[email protected]>, proto=ESMTP, daemon=MTA-v4, relay=localhost [127.0.0.1]
Aug  2 14:18:28 picus sm-mta[21173]: v72IIS0I021171: to=<[email protected]>, delay=00:00:00, xdelay=00:00:00, mailer=esmtp, pri=120347, relay=example.com. [my.servers.ip.address], dsn=4.0.0, stat=Deferred: Connection refused by example.com.

My Symfony controller code, config, and parameters -

Relevant controller code:

if ($form->isSubmitted() && $form->isValid()) {
    $data = $form->getData();

    $this->addFlash('success', 'Message sent successfully');

    $data['message'] = str_replace("\n.", "\n..", $data['message']);

    $mail = (new \Swift_Message())
        ->setSubject("[From My Website] - {$data['subject']}")
        ->setFrom($data['email'])
        ->setTo('[email protected]')
        ->setBody("{$data['name']} wrote the following message:\n\n{$data['message']}");

    $this->get('mailer')->send($mail);

    return $this->redirect($this->generateUrl('_home'));
}

config.yml:

# Swiftmailer Configuration
swiftmailer:
    transport: '%mailer_transport%'
    host: '%mailer_host%'
    username: '%mailer_user%'
    password: '%mailer_password%'
    port: '%mailer_port%'
    spool:
        type: file
        path: '%kernel.cache_dir%/swiftmailer/spool'

parameters.yml:

parameters:
    mailer_transport: sendmail
    mailer_host: 127.0.0.1
    mailer_user: null
    mailer_password: null
    mailer_port: null

What's really frustrating is that if I create a message using bin/console swiftmailer:email:send, and then flush the spool (bin/console swiftmailer:spool:send) it is sent properly. It's only when I create and send a message through my controller that there's an issue.

What am I doing wrong?

Beat answered 2/8, 2017 at 18:29 Comment(6)
what happens with bin/console swiftmailer:email:send --env=prod and bin/console swiftmailer:spool:send --env=prod. Is the message sent? You could have a different config for dev and prodBarkeeper
Some mail servers do not treat 127.0.0.1 the same as localhost or local.domain. Try using localhost instead of 127.0.0.1 in your config.Mechanistic
@Michel, yes, the email is sent. The console works in both dev and prod, while the controller code does not. I've checked my environment-specific config files, and there's no Swiftmailer settings within either of them. @tftd, neither using localhost nor 127.0.0.1 makes a difference. The same email deferment happens with the exact same log messages (the only difference is the date and time).Beat
Try deleting cache. Also if you have it working with bin/console and not Controller you can try debugging the container and compare the mailer service that's injected in both cases. Hope it helps.Crispi
I've been clearing the cache regularly, since I've been trying different solutions. I'll attempt to debug the container.Beat
Overall i would recommend using mailcatcher instead of sendmail. I had trouble using sendmail in combination with a differend phpframework and a proxy + firewall.Nighthawk
B
10

Ooof

It was a DNS error on my side that was causing the problem. Namely, that I forgot to point my MX records to Google's mail servers, so sendmail was taking the example.com portion of the destination address and trying to use it as a smtp relay, even though I didn't have a mail server set up.

Apologies for all the consternation. Hopefully my answer can be useful for others banging their heads against the wall.

Beat answered 7/8, 2017 at 22:3 Comment(0)
E
5

Why do you use the Sendmail Transport instead of SMTP Transport?

https://swiftmailer.symfony.com/docs/sending.html

Try this:

config.yml

# Swiftmailer Configuration
swiftmailer:
    transport: "%mailer_transport%"
    host:      "%mailer_host%"
    username:  "%mailer_user%"
    password:  "%mailer_password%"
    port: "%mailer_port%"
    encryption: "%mailer_encryption%"
    spool:     { type: memory }

parameters.yml

parameters:
    mailer_transport: smtp
    mailer_host: smtp.office365.com
    mailer_user: [email protected]
    mailer_password: my_password
    mailer_port: 587
    mailer_encryption: tls

Controller

$message = \Swift_Message::newInstance()
            ->setSubject('Subject')
            ->setFrom(array('[email protected]' => 'My name'))
            ->setTo(array($user->getMail()))
            ->setBcc(array('[email protected]', '[email protected]'))
            ->setBody(
                $this->renderView(
                    'template.html.twig',
                    array('vars' => $vars)
                ),
                'text/html'
            );

$this->get('mailer')->send($message);
Everlasting answered 6/8, 2017 at 10:5 Comment(4)
I've tried smtp... by default, it simply uses the sendmail that's on my system. My Google account has two-factor authentication, and Google has made it a lot more difficult to use their smtp server in that case (old SO answers regarding it are no longer relevant/correct). I might try using my ISP's smtp, but they like locking accounts for spam. And I don't use Office 365. Ultimately, there's no good reason not to use sendmail since it's there, and, again, it's not a sendmail problem (console emails work just fine) but a Swiftmailer or Symfony console vs. controller problemBeat
Did you create the transport and then create the mailer using your created transport? Like is explained in the swiftmailer doc swiftmailer.symfony.com/docs/sending.html#using-the-send-methodEverlasting
You don't need to create the transport manually in Symfony. You simply need to invoke $this->get('mailer')->send($message); The base controller grabs the Swiftmailer service, and then constructs a mailer using the values given in app/config/config.yml. And even with that, even manually trying with an explicitly created transport and mailer (because you're not the first person to suggest it here (see the answer below) or in the various GitHub issues that look remotely relevant), the problem persists. I'm not trying to be a jerk or anything, but it's not a matter of not following docsBeat
Regarding the docs, see: symfony.com/doc/current/email.html#sending-emails My code uses what's in the comments, which is equivalent to the uncommented code.Beat
R
2

I can suggest you to try this approach:

    $mailer = $container->get('mailer');
    $spool = $mailer->getTransport()->getSpool();
    $transport = $container->get('swiftmailer.transport.real');

    $sender     = 'your_sender';
    $recipient  = 'your_recipient';
    $title      = 'your_title';
    $body       = 'your_message';
    $charset    = "UTF-8";

    $email = $mailer->createMessage()
        ->setSubject($title)
        ->setFrom("$sender")
        ->setTo("$recipient")
        ->setCharset($charset)
        ->setContentType('text/html')
        ->setBody($body)
    ;

    $send = $mailer->send($email);
    $spool->flushQueue($transport);

You can wrap this into a send message of the simple YouMailService. Or you can insert this code into your controller. This will be enough.

Raoul answered 5/8, 2017 at 8:23 Comment(3)
Can you explain how does this approach change from the one OP tried?Rideout
@AlainTiemblo You know, I wasn't really correct. My approach really works in commands. But for controllers it doesn't matter. And I still hope it will help. In addition $spool->flushQueue($transport); will flush all messages and force send them.Raoul
The problem is that the messages created in the controller behave differently than messages created through the console. There's some sort of underlying difference in the code (either Swiftmailer or Symfony) when it comes to console vs. controller. All of my emails are properly sent to the spool... it's only the controller created emails that are deferred when the spool is flushed.Beat

© 2022 - 2024 — McMap. All rights reserved.