Trying to set up local docker-mailserver with docker-compose and nodemailer

Viewed 590

I am trying to set up a docker-mailserver instance to use the nodemailer module to send emails from in my local dev setup. Here's what my docker-compose.yml file looks like:

version: '3.1'

services:
  postgres:
    container_name: postgres
    image: postgres
    restart: always
    volumes:
      - $PWD/.dbData:/data/db
    networks:
      - skynet
    environment:
      POSTGRES_PASSWORD: <PASSWORD>
      POSTGRES_USER: <USER>
      POSTGRES_DB: <DB>
  mailserver:
    image: docker.io/mailserver/docker-mailserver:latest
    env_file: $PWD/mailserver.env
    hostname: mailserver
    domainname: example.com
    container_name: mailserver
    ports:
      - "25:25"
      - "143:143"
      - "587:587"
      - "993:993"
    volumes:
      - $PWD/.mailData/maildata:/var/mail
      - $PWD/.mailData/mailstate:/var/mail-state
      - $PWD/.mailData/maillogs:/var/log/mail
      - /etc/localtime:/etc/localtime:ro
      - ./config/:/tmp/docker-mailserver/
    environment:
      - ENABLE_SPAMASSASSIN=1
      - SPAMASSASSIN_SPAM_TO_INBOX=1
      - ENABLE_CLAMAV=1
      - ENABLE_FAIL2BAN=1
      - ENABLE_POSTGREY=1
      - ENABLE_SASLAUTHD=0
      - ONE_DIR=1
      - DMS_DEBUG=0
    cap_add:
      - NET_ADMIN
      - SYS_PTRACE
    restart: always
    networks: 
      - skynet
  adminer:
    image: adminer
    hostname: adminer
    ports:
      - '8080:8080'
    depends_on:
      - postgres
    networks:
      - skynet
  app:
    # ... app details
networks:
  skynet:

As per the docs, I copied the example mailserver.env file and setup.sh administrative script. When I try to run docker-compose up -d, I see the following in the docker logs for the mailserver container:

Jun 22 23:25:53 mailserver postfix/master[26133]: fatal: bind: private/proxywrite: Invalid argument

I think this might be causing an issue, because when I try to send a simple message with nodemailer (on the same machine), like so:

const nodemailer = require('nodemailer')

let transporter = nodemailer.createTransport({
  host: 'localhost', // <--- defaults to this anyway
  port: 587,
})

const message = {
  from: 'foo@example.com',
  to: '<MY_PERSONAL_EMAIL>@gmail.com',
  subject: 'YOUR CARS EXTENDED WARRANTY',
  text: 'WEVE BEEN TRYING TO REACH YOU ABOUT YOUR CARS EXTENDED WARRANTY',
  html: '<p>WEVE BEEN TRYING TO REACH YOU ABOUT YOUR CARS EXTENDED WARRANTY</p>',
}

transporter.sendMail(message).then(
  () => {
    console.log('success!')
  },
  (err) => {
    console.error('=========== error occurred', err)
  },
)

I get the following error:

error occurred Error: Unexpected socket close
    at Timeout._onTimeout (/path/to/nodemailer-test/node_modules/nodemailer/lib/smtp-transport/index.js:189:31)
    at listOnTimeout (internal/timers.js:551:17)
    at processTimers (internal/timers.js:494:7)

Any help would be greatly appreciated.

1 Answers

I guess you are running your node code in the app container.

You were trying to talk to localhost:587 from there which would be your app container's port 587, not the one available on the service mailserver (which you also bound to your host machine).

You might have wanted to talk to the host there, but getting the host machine IP in docker is not trivial. Fortunately it is also not needed in this case: Since both containers are part of the same docker-compose project, they are automatically routed internally by the service name.

This would let your app container talk to the mailserver container directly:

let transporter = nodemailer.createTransport({
  host: 'mailserver',
  port: 587,
})

Some more troubleshooting:

  • mailserver is only part of the skynet network. Make sure that app does belong to that, too. netcat/telnet/ping can help you troubleshoot: docker-compose exec -it app bash - then inside the container: ping mailserver
  • Compare your mailserver service configuration to https://github.com/docker-mailserver/docker-mailserver/blob/v10.0.0/docker-compose.yml - it seems you used an older configuration version but mailserver/docker-mailserver:latest refers to v10. It seems their example configuration from README.md/docker hub page does not reflect that yet. Since it is the first release of v10, you might want to try with mailserver/docker-mailserver:9 (it is good practice anyways to "pin" the major version of used dependencies)
  • Try to send your mail via the other ports. I am using STARTTLS on port 25 with docker-mailserver for example to send mails from my apps.
Related