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=<Test@test.com>, size=347, class=0, nrcpts=1, msgid=<91d4a1a70de9fed0a2c04e682e435405@swift.generated>, proto=ESMTP, daemon=MTA-v4, relay=localhost [127.0.0.1]
Aug  2 14:18:28 picus sm-mta[21173]: v72IIS0I021171: to=<person@gmail.com>, 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('person@gmail.com')
        ->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?

Major Productions
  • 5,914
  • 13
  • 70
  • 149
  • 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 prod – Michel Aug 05 '17 at 04:09
  • 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. – tftd Aug 05 '17 at 08:31
  • @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). – Major Productions Aug 05 '17 at 14:51
  • 1
    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. – Keloo Aug 06 '17 at 17:09
  • I've been clearing the cache regularly, since I've been trying different solutions. I'll attempt to debug the container. – Major Productions Aug 06 '17 at 17:24
  • Overall i would recommend using mailcatcher instead of sendmail. I had trouble using sendmail in combination with a differend phpframework and a proxy + firewall. – Spears Aug 09 '17 at 20:45

3 Answers3

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.

Major Productions
  • 5,914
  • 13
  • 70
  • 149
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: user@example.com
    mailer_password: my_password
    mailer_port: 587
    mailer_encryption: tls

Controller

$message = \Swift_Message::newInstance()
            ->setSubject('Subject')
            ->setFrom(array('user@example.com' => 'My name'))
            ->setTo(array($user->getMail()))
            ->setBcc(array('copy1@example.com', 'copy2@example.com'))
            ->setBody(
                $this->renderView(
                    'template.html.twig',
                    array('vars' => $vars)
                ),
                'text/html'
            );

$this->get('mailer')->send($message);
JGrinon
  • 1,453
  • 1
  • 14
  • 36
  • 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 problem – Major Productions Aug 06 '17 at 13:51
  • Did you create the transport and then create the mailer using your created transport? Like is explained in the swiftmailer doc https://swiftmailer.symfony.com/docs/sending.html#using-the-send-method – JGrinon Aug 06 '17 at 15:55
  • 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 docs – Major Productions Aug 06 '17 at 16:25
  • Regarding the docs, see: http://symfony.com/doc/current/email.html#sending-emails My code uses what's in the comments, which is equivalent to the uncommented code. – Major Productions Aug 06 '17 at 16:29
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.

staskrak
  • 873
  • 2
  • 10
  • 22
  • Can you explain how does this approach change from the one OP tried? – Alain Tiemblo Aug 05 '17 at 09:19
  • @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. – staskrak Aug 05 '17 at 09:30
  • 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. – Major Productions Aug 05 '17 at 18:56