Joplin server email config - TLS problems

Joplin Server Version: 2.11.1
Running in Docker Compose v2.18.1
Docker Engine - Community v24.0.2
containerd v1.6.21
runc v1.1.7
OS: Ubuntu Server 22.04.02 LTS
Kernel: 5.15.0-72-generic (x86)

Mailcow version: 2023-05a
Postfix version: mailcow/postfix:arm64-dev
Dovecot version: mailcow/dovecot:arm64-dev
Running in Docker Compose v2.18.1
Docker Engine - Community v24.0.1
containerd: 1.6.21
runc: 1.1.7
OS: Ubuntu 22.04.02 (ARM64)
Kernel: 5.15.0-1035-oracle

I'm trying to get email working from Joplin Server. I'm using my personal SMTP server which is Mailcow. The MTA is Postfix. Just out front, SMTP is working just fine for all my other mail clients, Joplin is the only one failing to authenticate. When I start the Joplin container I see this in the logs:

2023-05-30 18:16:27: App: Starting server v2.11.1 (prod) on port 22300 and PID 7...
2023-05-30 18:16:27: App: Checking for time drift using NTP server: pool.ntp.org:123
2023-05-30 18:16:27: App: NTP time offset: -46ms
2023-05-30 18:16:27: App: Running in Docker: true
2023-05-30 18:16:27: App: Public base URL: https://joplin.mydomain.com
2023-05-30 18:16:27: App: API base URL: https://joplin.mydomain.com
2023-05-30 18:16:27: App: User content base URL: https://joplin.mydomain.com
2023-05-30 18:16:27: App: Log dir: /home/joplin/packages/server/logs
2023-05-30 18:16:27: App: DB Config: {
  client: 'pg',
  name: 'joplin',
  slowQueryLogEnabled: false,
  slowQueryLogMinDuration: 1000,
  autoMigration: true,
  user: 'joplin',
  password: '********',
  port: 5432,
  host: 'joplin_db'
}
2023-05-30 18:16:27: App: Mailer Config: {
  enabled: true,
  host: 'mail.mydomain.com',
  port: 587,
  security: 'tls',
  authUser: 'joplin@mydomain.com',
  authPassword: '********',
  noReplyName: 'Joplin Server',
  noReplyEmail: 'joplin@mydomain.com'
}
2023-05-30 18:16:27: App: Content driver: { type: 1 }
2023-05-30 18:16:27: App: Content driver (fallback): null
2023-05-30 18:16:27: App: Trying to connect to database...
2023-05-30 18:16:27: App: Connection check: {
  latestMigration: { name: '20221020143305_task_states.js', done: true },
  isCreated: true,
  error: null
}
2023-05-30 18:16:27: App: Auto-migrating database...
2023-05-30 18:16:27: App: Latest migration: { name: '20221020143305_task_states.js', done: true }
2023-05-30 18:16:27: App: Performing main storage check...
2023-05-30 18:16:27: App: Database storage is special and cannot be checked this way. If the connection to the database was successful then the storage driver should work too.
2023-05-30 18:16:27: App: Starting services...
2023-05-30 18:16:27: ShareService: Starting maintenance...
2023-05-30 18:16:27: EmailService: Starting maintenance...
2023-05-30 18:16:27: TaskService: Scheduling #1 (Delete expired tokens): 0 */6 * * *
2023-05-30 18:16:27: TaskService: Scheduling #2 (Update total sizes): 0 * * * *
2023-05-30 18:16:27: TaskService: Scheduling #3 (Process oversized accounts): 30 */2 * * *
2023-05-30 18:16:27: TaskService: Scheduling #6 (Delete expired sessions): 0 */6 * * *
2023-05-30 18:16:27: TaskService: Scheduling #7 (Compress old changes): 0 0 */2 * *
2023-05-30 18:16:27: TaskService: Scheduling #8 (Process user deletions): 10 * * * *
2023-05-30 18:16:27: App: Call this for testing: `curl https://joplin.mydomain.com/api/ping`
2023-05-30 18:16:28: ShareService: Maintenance completed in 204ms
2023-05-30 18:16:28: [error] EmailService: Could not run maintenance: [Error: C0F790488C7F0000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:355:
] {
  library: 'SSL routines',
  reason: 'wrong version number',
  code: 'ESOCKET',
2023-05-30 18:16:28: EmailService: Maintenance completed in 302ms
  command: 'CONN'
}

On the Postfix side I see the connection attempt from my Joplin server IP, then after 10 seconds the SMTP server shows a lost connection and disconnect.

05/30/2023, 07:06:25 PM	info	disconnect from unknown[<Joplin IP>] unknown=0/3 commands=0/3
05/30/2023, 07:06:25 PM	info	lost connection after UNKNOWN from unknown[<Joplin IP>]
05/30/2023, 07:06:15 PM	info	connect from unknown[<Joplin IP>]

As far as I know I've tries all the different iterations of the MAILER_SECURITY environment variable in my Joplin docker-compose file. The current config shows what I think is probably the best error state (The other error state was something to the effect of "no credentials supplied for PLAIN").

For reference, my SMTP is listening on both 465 and 587 for both explicit TLS and STARTTLS connections. Neither port works, and none of the MAILER_SECURITY values works either.

Here's my Joplin compose:

  joplin_db:
    image: postgres:15
    volumes:
      - $DOCKERDIR/appdata/joplin/data/postgres:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    restart: unless-stopped
    environment:
      - POSTGRES_PASSWORD=$JOPLIN_POSTGRES_PASSWORD
      - POSTGRES_USER=$JOPLIN_POSTGRES_USER
      - POSTGRES_DB=$JOPLIN_POSTGRES_DATABASE
      - TZ=US/Pacific
    networks:
      t2_proxy:
  joplin_app:
    image: joplin/server:latest
    depends_on:
      - joplin_db
    ports:
      - "22300:22300"
    restart: unless-stopped
    volumes:
      - $DOCKERDIR/appdata/joplin/storage:/mnt/storage
    environment:
      - APP_PORT=22300
      - APP_BASE_URL=$JOPLIN_APP_BASE_URL
      - DB_CLIENT=pg
      - POSTGRES_PASSWORD=$JOPLIN_POSTGRES_PASSWORD
      - POSTGRES_DATABASE=$JOPLIN_POSTGRES_DATABASE
      - POSTGRES_USER=$JOPLIN_POSTGRES_USER
      - POSTGRES_PORT=$JOPLIN_POSTGRES_PORT
      - POSTGRES_HOST=joplin_db
      - TZ=US/Pacific
      - MAILER_ENABLED=1
      - MAILER_HOST=mail.mydomain.com
      - MAILER_PORT=465
      - MAILER_SECURITY=secure
      - MAILER_AUTH_USER=$JOPLIN_MAIL_USER
      - MAILER_AUTH_PASSWRD=$JOPLIN_MAIL_PASSWORD
      - MAILER_NOREPLY_NAME=Joplin Server
      - MAILER_NOREPLY_EMAIL=$JOPLIN_MAIL_USER
    labels:
      - "traefik.enable=true"
      ## HTTP Routers
      - "traefik.http.routers.joplin-rtr.entrypoints=https"
      - "traefik.http.routers.joplin-rtr.rule=Host(`joplin.$DOMAINNAME_CLOUD_SERVER`)"
      ## Middlewares
      - "traefik.http.routers.joplin-rtr.middlewares=chain-no-auth@file"
      ## HTTP Services
      - "traefik.http.routers.joplin-rtr.service=joplin-svc"
      - "traefik.http.services.joplin-svc.loadbalancer.server.port=22300"
    networks:
      t2_proxy:

The error is strange with this portion:

library: 'SSL routines',
reason: 'wrong version number',
code: 'ESOCKET',

It makes me think that Joplin doesn't support the TLS version that Postfix is looking for, but best I can tell they're both using compatible versions and algorithms.

Any ideas here?

If you just run curl https://joplin.mydomain.com/api/ping does it work? I found this: curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number - Stack Overflow that mentions it might need to be http, not https. Also maybe try different ports after joplin.mydomain.com, someone mentioned that docker wanted 443 to be exposed to the internet. I usually use a netstat -tulnp in linux to get open ports. (I'm looking now and it looks like netstat is deprecated but still available)

Hi there. Yeah the API endpoint is working and responding as expected (https only, http has an empty response. This is expected as far as I'm aware).

The post you reference points to the issue I was suspecting at the end of my post where there's a TLS version mismatch happening I'm just not sure how to force Joplin or Postfix to use specific TLS versions. I was reviewing the Joplin code to see what its using for SMTP connections and the module used is Nodemailer. Nodemailer's documentation makes it look like my config will tell it to use STARTTLS which my mail server supports. So the way I'm understanding it is that Joplin, via Nodemailer will open a connection to my mail server via SMTP using plaintext on port 587. The server will respond and request a TLS session and they'll negotiate the options.
The way I'm reading this error

[error] EmailService: Could not run maintenance: [Error: C077BB670E7F0000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:355:
] {
  library: 'SSL routines',
  reason: 'wrong version number',
  code: 'ESOCKET',
  command: 'CONN'
}

the negotiation begins but they don't agree on the TLS version at which point Nodemailer ends the connection with this error and eventually my SMTP server closes its side as well.

So, the big question is what TLS version is each side trying to use? I see that Nodemailer seems to be using the Node.js built in class tls.TLSSocket but I don't know what options are being passed to that constructor.
This doc refers to the STARTTLS IETF standard RFC 3207 but I don't see any mention of TLS versions being dictated. I'm guessing that's purposely left open to allow for new TLS versions as they evolve.

At this point I think I'm down to doing a packet capture to see if I can determine the version mismatch and seeing if I can either upgrade one to TLS1.3 or (less preferred) downgrade one.

1 Like

Yes, packet capture might be your best bet at this point. You may have already seen this since it seems like you have done your research, but node.js - NPM request - Get TLS version - Stack Overflow mentions an API call to howsmyssl.com that will tell you the TLS version. I went to the site and it seems to imply that you need a subscription to use their API but it looks like it's free for your own servers: API · How's My SSL? Worth a try, although I'm not sure how difficult it would be to make an API call from the Joplin server.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.