A self-managed GitLab sends mail for sign-up confirmations, password resets, merge request and pipeline notifications. The Linux package defaults to a local sendmail, and the Docker image has no mail server at all — so unless you point it at an SMTP relay, those emails either go nowhere or arrive unauthenticated. This guide covers the Linux package (Omnibus) and the official Docker image, which reads the same settings.
| Setting | Value |
|---|---|
| SMTP host | smtp.postwing.app |
| Port | 587 |
| Encryption | STARTTLS (the connection is upgraded to TLS before login) |
| Username | The login of an SMTP token for your domain |
| Password | The password of that token — shown once, when the token is created |
Add these lines to /etc/gitlab/gitlab.rb. gitlab_email_from is the address every notification comes from, so it must be on your verified domain:
# /etc/gitlab/gitlab.rb
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.postwing.app"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "token-login@your-domain.com"
gitlab_rails['smtp_password'] = "your-token-password"
gitlab_rails['smtp_domain'] = "your-domain.com"
gitlab_rails['smtp_authentication'] = "plain"
gitlab_rails['smtp_enable_starttls_auto'] = true # STARTTLS on 587
gitlab_rails['smtp_tls'] = false # true only for port 465
gitlab_rails['smtp_openssl_verify_mode'] = 'peer'
gitlab_rails['gitlab_email_from'] = 'gitlab@your-domain.com'
gitlab_rails['gitlab_email_display_name'] = 'GitLab'
gitlab_rails['gitlab_email_reply_to'] = 'noreply@your-domain.com'587 needs smtp_enable_starttls_auto = true and smtp_tls = false. Port 465 needs smtp_tls = true. Setting both to true stops GitLab from sending at all. Avoid a single quote in the password — GitLab's docs warn that Ruby and YAML string delimiters break config processing. For port 465 instead:
# Port 465 (implicit TLS) instead of 587
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_tls'] = true
gitlab_rails['smtp_enable_starttls_auto'] = falseApply the configuration:
sudo gitlab-ctl reconfigure The official image accepts any gitlab.rb setting through GITLAB_OMNIBUS_CONFIG. It is evaluated on every start and never written to gitlab.rb, so keep it in the compose file and run docker compose up -d after changing it:
# docker-compose.yml
services:
gitlab:
image: gitlab/gitlab-ce:latest
hostname: gitlab.your-domain.com
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://gitlab.your-domain.com'
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.postwing.app"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "token-login@your-domain.com"
gitlab_rails['smtp_password'] = "your-token-password"
gitlab_rails['smtp_domain'] = "your-domain.com"
gitlab_rails['smtp_authentication'] = "plain"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['gitlab_email_from'] = 'gitlab@your-domain.com' Alternatively, edit /etc/gitlab/gitlab.rb inside the container (docker exec -it gitlab editor /etc/gitlab/gitlab.rb) and run docker restart gitlab — GitLab reconfigures itself on start.
There is no test button in the Admin area; use the Rails console (in Docker, prefix it with docker exec -it gitlab):
sudo gitlab-rails console
# at the console prompt
Notify.test_email('you@example.com', 'GitLab SMTP test', 'It works.').deliver_now If nothing arrives, check ActionMailer::Base.delivery_method in the same console — it must return :smtp — and ActionMailer::Base.smtp_settings for the values GitLab actually loaded.
With encrypted configuration enabled, the SMTP login and password can move out of gitlab.rb into an encrypted file. Remove smtp_user_name and smtp_password from gitlab.rb afterwards and reconfigure:
sudo gitlab-rake gitlab:smtp:secret:edit EDITOR=vim
# contents of the encrypted file
user_name: 'token-login@your-domain.com'
password: 'your-token-password'| Error | Cause and fix |
|---|---|
SSL_connect returned=1 ... wrong version number | smtp_tls = true on port 587. Use STARTTLS there, or switch to 465. |
:enable_starttls and :tls are mutually exclusive | Both flags are true. Set the one that does not match the port to false. |
Net::OpenTimeout | Outbound port blocked — set smtp_port to 8587, or 8465 with smtp_tls. |
535 Authentication failed | Wrong token login or password. |
| Console test works, notifications do not | An external Sidekiq without the SMTP settings, or routing rules that skip the mailers queue. |
| Sender rejected or mail in spam | gitlab_email_from is not on your verified domain. |
On a self-managed Linux package (Omnibus) install they are the gitlab_rails['smtp_*'] keys in /etc/gitlab/gitlab.rb. There is no SMTP form in the Admin area. After editing the file, run sudo gitlab-ctl reconfigure to apply it.
smtp_enable_starttls_auto upgrades a plain connection with STARTTLS — use it with port 587. smtp_tls opens an encrypted connection from the first byte — use it with port 465. They are mutually exclusive: with both set to true, GitLab refuses to send.
Start sudo gitlab-rails console and run Notify.test_email('you@example.com', 'Subject', 'Body').deliver_now. Any SMTP error is printed straight to the console, which is the fastest way to see what is wrong.
Put the same gitlab_rails lines in the GITLAB_OMNIBUS_CONFIG environment variable, or edit /etc/gitlab/gitlab.rb inside the container and run docker restart gitlab. GITLAB_OMNIBUS_CONFIG is evaluated on every start and is not written to gitlab.rb, so it must stay in your compose file.
The TLS mode does not match the port. Port 587 starts unencrypted and needs smtp_enable_starttls_auto = true with smtp_tls = false; port 465 needs smtp_tls = true. Fix the pair and run gitlab-ctl reconfigure.
Most GitLab mail is sent by Sidekiq from the mailers queue. If Sidekiq runs on a separate server, that server's gitlab.rb needs the same SMTP settings; if you use Sidekiq routing rules, make sure the mailers queue is still processed.