Milestone #79
opensetup Redmine Using internal mailserver
90%
Description
Yes, absolutely! You can configure your Redmine instance to use this Postfix mail server as its SMTP relay. Here's how to set it up:
1. First, Update Redmine Configuration ¶
Create or update a ConfigMap for Redmine's email configuration:
# redmine-email-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: redmine-email-config
data:
configuration.yml: |
default:
email_delivery:
delivery_method: :smtp
smtp_settings:
address: "postfix" # Postfix service name in Kubernetes
port: 587
domain: "yourdomain.com"
authentication: :none # No auth to Postfix (internal traffic)
enable_starttls_auto: false # Postfix handles TLS to Gmail
openssl_verify_mode: 'none' # For self-signed certs if needed
2. Mount the Configuration in Redmine Deployment ¶
Update your Redmine deployment to use this ConfigMap:
# redmine-deployment-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redmine
spec:
template:
spec:
containers:
- name: redmine
volumeMounts:
- name: email-config
mountPath: /usr/src/redmine/config/configuration.yml
subPath: configuration.yml
volumes:
- name: email-config
configMap:
name: redmine-email-config
3. Alternative: Using Redmine Environment Variables ¶
If your Redmine image supports environment variables for email configuration:
# redmine-deployment-env.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redmine
spec:
template:
spec:
containers:
- name: redmine
env:
- name: REDMINE_EMAIL_DELIVERY_METHOD
value: "smtp"
- name: REDMINE_SMTP_HOST
value: "postfix" # Kubernetes service name
- name: REDMINE_SMTP_PORT
value: "587"
- name: REDMINE_SMTP_DOMAIN
value: "yourdomain.com"
- name: REDMINE_SMTP_STARTTLS_AUTO
value: "false"
- name: REDMINE_SMTP_AUTHENTICATION
value: "none"
4. Test Redmine Email Functionality ¶
Method 1: Test from Redmine Console¶
# Access Redmine pod
kubectl exec -it redmine-pod -- /bin/bash
# Start Rails console
bundle exec rails console
# Test email sending
ActionMailer::Base.mail(
from: 'redmine@yourdomain.com',
to: 'test@example.com',
subject: 'Test from Redmine',
body: 'This is a test email from Redmine'
).deliver_now
Method 2: Use Redmine's Test Function¶
- Log into Redmine as Admin
- Go to Administration → Settings → Email notifications
- Click "Send a test email"
- Enter your email address
5. Customizing Redmine's "From" Address ¶
To ensure Redmine uses your Gmail address properly:
Option A: Configure in Redmine Settings¶
# Update configuration.yml
email_delivery:
smtp_settings:
# ... existing settings ...
# Add email_from setting
email_from: '"Redmine" <your-email@gmail.com>'
Option B: Use Postfix Header Rewriting¶
Ensure your Postfix header_checks ConfigMap handles Redmine emails:
# Update header_checks in postfix ConfigMap
header_checks: |
# Rewrite ALL From headers to use your Gmail
/^From:.*/ REPLACE From: "Redmine System" <your-email@gmail.com>
# Or be more specific for Redmine emails
/^From:.*redmine.*/ REPLACE From: "Redmine" <your-email@gmail.com>
/^From:.*@yourdomain.com/ REPLACE From: "Redmine" <your-email@gmail.com>
# Ensure proper headers
/^Reply-To:.*/ REPLACE Reply-To: "Redmine" <your-email@gmail.com>
/^Sender:.*/ REPLACE Sender: your-email@gmail.com
6. Complete Example with Bitnami Redmine ¶
If you're using the Bitnami Redmine chart:
# values.yaml for Bitnami Redmine
smtpHost: "postfix"
smtpPort: 587
smtpUser: ""
smtpPassword: ""
smtpProtocol: ""
smtpTls: false
smtpAuth: ""
extraEnvVars:
- name: REDMINE_EMAIL_FROM
value: "your-email@gmail.com"
7. Verify the Flow ¶
The email flow will be:
Redmine → Postfix (K8s Service) → Gmail SMTP → Recipient
↑ ↑
No auth needed Uses your Gmail auth
(internal traffic) (App Password)
8. Common Issues and Solutions ¶
Issue 1: Connection refused¶
# Check Postfix is running
kubectl get pods -l app=postfix
# Check logs
kubectl logs postfix-pod
# Test connectivity from Redmine pod
kubectl exec redmine-pod -- telnet postfix 587
Issue 2: Emails not sending¶
# Check Postfix mail queue
kubectl exec postfix-pod -- postqueue -p
# Check Postfix logs
kubectl logs postfix-pod | grep -i "sasl\|tls\|relay"
Issue 3: Gmail rejecting emails¶
# Check for authentication errors
kubectl logs postfix-pod | grep -i "authentication\|535\|550"
9. Monitoring Email Delivery ¶
# Add sidecar for mail log monitoring
# postfix-deployment-with-sidecar.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: postfix
spec:
template:
spec:
containers:
- name: postfix
# ... existing postfix container ...
- name: mail-log-tailer
image: alpine:latest
command: ["sh", "-c"]
args:
- tail -f /var/log/mail.log
volumeMounts:
- name: mail-logs
mountPath: /var/log
10. Quick Test Commands ¶
# Test email sending from within cluster
cat << EOF | kubectl run -it --rm --image=alpine:latest test-email -- sh
apk add mailx
echo "Test email body" | mail -s "Test Subject" test@example.com \
-r "Redmine <your-email@gmail.com>" \
-S smtp="postfix:587"
EOF
This setup allows Redmine to send notifications (issue updates, password resets, etc.) through your Postfix relay, which then sends them via Gmail with your Gmail address as the sender. The emails should have better deliverability since they're properly authenticated through Gmail's SMTP servers.
Updated by Daniele Cruciani about 1 month ago
- Description updated (diff)
Updated by Daniele Cruciani about 1 month ago
Alternative¶
Using Gmail Directly from Kubernetes (No Postfix)¶
This is actually simpler and often more reliable. Here's how to configure Redmine and other services to use Gmail SMTP directly.
1. Why Go Direct to Gmail?¶
Advantages:
- Simpler setup
- No intermediate mail server to maintain
- Better deliverability (Gmail's reputation)
- Built-in TLS/security
- Monitoring via Gmail
Disadvantages:
- Gmail's sending limits (500 recipients/day free, 2,000/day GSuite)
- Requires app password for each service
- No queuing if Gmail is down
2. Redmine Direct Gmail Configuration¶
Option A: Redmine Configuration File¶
Create a ConfigMap for Redmine:
# redmine-gmail-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: redmine-email-config
data:
configuration.yml: |
default:
email_delivery:
delivery_method: :smtp
smtp_settings:
address: "smtp.gmail.com"
port: 587
domain: "gmail.com" # or your custom domain
authentication: :plain
enable_starttls_auto: true
user_name: "your-email@gmail.com"
password: "your-app-password-here"
openssl_verify_mode: 'peer'
# Optional: Force specific sender address
email_from: '"Redmine Notifications" <your-email@gmail.com>'
# For newer Redmine versions using environment variables
.env: |
REDMINE_EMAIL_DELIVERY_METHOD=smtp
REDMINE_SMTP_HOST=smtp.gmail.com
REDMINE_SMTP_PORT=587
REDMINE_SMTP_USER=your-email@gmail.com
REDMINE_SMTP_PASSWORD=your-app-password
REDMINE_SMTP_STARTTLS_AUTO=true
REDMINE_SMTP_AUTHENTICATION=plain
REDMINE_EMAIL_FROM="Redmine <your-email@gmail.com>"
Option B: Redmine Deployment with Environment Variables¶
# redmine-deployment-gmail.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redmine
spec:
template:
spec:
containers:
- name: redmine
env:
# Gmail SMTP Configuration
- name: REDMINE_EMAIL_DELIVERY_METHOD
value: "smtp"
- name: REDMINE_SMTP_HOST
value: "smtp.gmail.com"
- name: REDMINE_SMTP_PORT
value: "587"
- name: REDMINE_SMTP_DOMAIN
value: "gmail.com"
- name: REDMINE_SMTP_USER
valueFrom:
secretKeyRef:
name: gmail-credentials
key: username
- name: REDMINE_SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: gmail-credentials
key: password
- name: REDMINE_SMTP_AUTHENTICATION
value: "plain"
- name: REDMINE_SMTP_ENABLE_STARTTLS_AUTO
value: "true"
- name: REDMINE_EMAIL_FROM
value: '"Redmine" <your-email@gmail.com>'
- name: REDMINE_EMAIL_SUBJECT_PREFIX
value: "[Redmine]"
# For Bitnami Redmine image
- name: SMTP_HOST
value: "smtp.gmail.com"
- name: SMTP_PORT
value: "587"
- name: SMTP_USER
valueFrom:
secretKeyRef:
name: gmail-credentials
key: username
- name: SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: gmail-credentials
key: password
- name: SMTP_PROTOCOL
value: ""
- name: SMTP_AUTH
value: "login"
- name: SMTP_TLS
value: "true"
Create Gmail Credentials Secret:¶
kubectl create secret generic gmail-credentials \
--from-literal=username='your-email@gmail.com' \
--from-literal=password='your-16-char-app-password'
3. Other Services Using Gmail Directly¶
Jenkins:¶
# jenkins-values.yaml (if using Helm)
controller:
JCasC:
defaultConfig: true
configScripts:
email: |
unclassified:
mailer:
charset: "UTF-8"
replyToAddress: "your-email@gmail.com"
smtpHost: "smtp.gmail.com"
smtpPort: 587
smtpAuthUsername: "your-email@gmail.com"
smtpAuthPassword: ${SMTP_PASSWORD}
useSsl: false
useTls: true
additionalSecrets:
- name: smtp-password
value: "your-app-password"
envVars:
- name: SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: gmail-credentials
key: password
GitLab:¶
# gitlab-values.yaml
global:
appConfig:
email:
enabled: true
from: "gitlab@yourdomain.com"
display_name: "GitLab"
subject_suffix: ""
smtp:
enabled: true
address: "smtp.gmail.com"
port: 587
user_name: "your-email@gmail.com"
password:
secret: gmail-credentials
key: password
authentication: "login"
starttls_auto: true
openssl_verify_mode: "peer"
WordPress:¶
# wordpress-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress
spec:
template:
spec:
containers:
- name: wordpress
env:
- name: WORDPRESS_DB_HOST
value: "mysql"
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-password
key: password
# SMTP Configuration via WP Mail SMTP plugin
- name: WPMS_SMTP_HOST
value: "smtp.gmail.com"
- name: WPMS_SMTP_PORT
value: "587"
- name: WPMS_SMTP_USER
valueFrom:
secretKeyRef:
name: gmail-credentials
key: username
- name: WPMS_SMTP_PASS
valueFrom:
secretKeyRef:
name: gmail-credentials
key: password
- name: WPMS_SMTP_AUTH
value: "true"
- name: WPMS_SMTP_SECURE
value: "tls"
- name: WPMS_FROM_EMAIL
value: "your-email@gmail.com"
- name: WPMS_FROM_NAME
value: "WordPress Site"
Generic Application (Node.js/Python/etc.):¶
# app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
containers:
- name: app
env:
- name: SMTP_HOST
value: "smtp.gmail.com"
- name: SMTP_PORT
value: "587"
- name: SMTP_USER
valueFrom:
secretKeyRef:
name: gmail-credentials
key: username
- name: SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: gmail-credentials
key: password
- name: EMAIL_FROM
value: '"My App" <your-email@gmail.com>'
4. Centralized SMTP Secret Management¶
Create a single secret for all services:
# Create generic Gmail secret
kubectl create secret generic smtp-gmail \
--from-literal=host='smtp.gmail.com' \
--from-literal=port='587' \
--from-literal=username='your-email@gmail.com' \
--from-literal=password='your-app-password' \
--from-literal=from-email='your-email@gmail.com' \
--from-literal=from-name='Kubernetes Services'
5. Using Sidecar SMTP Proxy (Alternative)¶
If apps don't support SMTP configuration easily, use a sidecar:
# smtp-sidecar.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-with-smtp
spec:
template:
spec:
containers:
- name: main-app
# Your main application
env:
- name: SMTP_HOST
value: "localhost" # Points to sidecar
- name: SMTP_PORT
value: "1025"
- name: smtp-proxy
image: namshi/smtp
env:
- name: RELAY_HOST
value: "smtp.gmail.com"
- name: RELAY_PORT
value: "587"
- name: RELAY_USERNAME
valueFrom:
secretKeyRef:
name: gmail-credentials
key: username
- name: RELAY_PASSWORD
valueFrom:
secretKeyRef:
name: gmail-credentials
key: password
ports:
- containerPort: 1025
6. Testing Gmail Connection¶
Create a test pod to verify SMTP works:
# test-smtp.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-smtp
spec:
containers:
- name: test
image: alpine:latest
command: ["sh", "-c"]
args:
- |
apk add --no-cache swaks
echo "Testing Gmail SMTP..."
swaks \
--to recipient@example.com \
--from your-email@gmail.com \
--server smtp.gmail.com:587 \
--auth LOGIN \
--auth-user "your-email@gmail.com" \
--auth-password "$(cat /etc/smtp/password)" \
-tls
env:
- name: SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: gmail-credentials
key: password
volumeMounts:
- name: smtp-password
mountPath: /etc/smtp
volumes:
- name: smtp-password
secret:
secretName: gmail-credentials
restartPolicy: Never
7. Monitoring and Limits¶
Gmail Limits to Know:¶
- Free Gmail: 500 recipients/day, 100 emails/hour
- G Suite: 2,000 recipients/day, 1,500 emails/hour
- Message size: 25MB total, ~20MB after encoding
Create a Monitoring Sidecar:¶
# monitoring sidecar
- name: smtp-monitor
image: python:3.9-alpine
command: ["python", "-c"]
args:
- |
import smtplib, time, os
from email.mime.text import MIMEText
def test_smtp():
try:
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(os.getenv('SMTP_USER'), os.getenv('SMTP_PASSWORD'))
server.quit()
print(f"{time.ctime()}: SMTP OK")
return True
except Exception as e:
print(f"{time.ctime()}: SMTP FAILED - {e}")
return False
while True:
test_smtp()
time.sleep(300) # Test every 5 minutes
env:
- name: SMTP_USER
valueFrom:
secretKeyRef:
name: gmail-credentials
key: username
- name: SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: gmail-credentials
key: password
8. Handling Multiple Gmail Accounts¶
If you need different sender addresses:
# Create multiple secrets
kubectl create secret generic gmail-redmine \
--from-literal=username='redmine@gmail.com' \
--from-literal=password='app-pass-1'
kubectl create secret generic gmail-jenkins \
--from-literal=username='jenkins@gmail.com' \
--from-literal=password='app-pass-2'
kubectl create secret generic gmail-alerts \
--from-literal=username='alerts@gmail.com' \
--from-literal=password='app-pass-3'
9. Security Best Practices¶
- Use App Passwords, not your main password
- Regularly rotate app passwords (every 90 days)
- Monitor usage in Google Account → Security
- Set up alerts for unusual activity
- Use separate accounts for different services if possible
10. Troubleshooting Common Issues¶
Error: "534-5.7.14 Please log in"¶
# Enable access for "less secure apps" temporarily
# Or visit: https://accounts.google.com/DisplayUnlockCaptcha
Error: "550-5.7.1 Daily sending limit exceeded"¶
- Reduce email volume
- Queue emails and send in batches
- Consider a paid service for high volume
Error: "Connection refused"¶
# Check if port 587 is open from your cluster
kubectl run -it --rm --image=alpine:latest test-net -- nc -zv smtp.gmail.com 587
# If blocked, use 465 with SSL instead
SMTP_PORT: "465"
SMTP_TLS: "true" # not STARTTLS
11. Complete Example: Redmine with Gmail¶
Here's the full setup:
# 1. Create Gmail secret
kubectl create secret generic gmail-redmine \
--from-literal=username='your-email@gmail.com' \
--from-literal=password='abcd efgh ijkl mnop'
# 2. Apply Redmine configuration
kubectl apply -f redmine-gmail.yaml
Where redmine-gmail.yaml is:
# redmine-gmail.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redmine
spec:
template:
spec:
containers:
- name: redmine
image: redmine:latest
env:
- name: REDMINE_SMTP_HOST
value: "smtp.gmail.com"
- name: REDMINE_SMTP_PORT
value: "587"
- name: REDMINE_SMTP_USER
valueFrom:
secretKeyRef:
name: gmail-redmine
key: username
- name: REDMINE_SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: gmail-redmine
key: password
- name: REDMINE_SMTP_AUTHENTICATION
value: "plain"
- name: REDMINE_SMTP_ENABLE_STARTTLS_AUTO
value: "true"
- name: REDMINE_EMAIL_FROM
value: '"Redmine" <your-email@gmail.com>'
---
apiVersion: v1
kind: Service
metadata:
name: redmine
spec:
ports:
- port: 3000
selector:
app: redmine
This direct approach is simpler and often works better than running your own Postfix when you're just using Gmail as the outgoing mail server anyway.
Updated by Daniele Cruciani about 1 month ago
- Status changed from new to confirmed
- Assignee set to Daniele Cruciani
- % Done changed from 0 to 90