dockerize smtp-proxy (#118)

This commit is contained in:
KM Koushik
2025-03-20 21:56:12 +11:00
committed by GitHub
parent 5465e2ec74
commit ecd28428d2
5 changed files with 141 additions and 53 deletions

View File

@@ -23,6 +23,13 @@ jobs:
os: os:
- warp-ubuntu-latest-x64-2x - warp-ubuntu-latest-x64-2x
- warp-ubuntu-latest-arm64-2x - warp-ubuntu-latest-arm64-2x
app:
- name: unsend
dockerfile: ./docker/Dockerfile
context: .
- name: smtp-proxy
dockerfile: ./Dockerfile
context: ./apps/smtp-server
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -53,23 +60,23 @@ jobs:
GIT_SHA="$(git rev-parse HEAD)" GIT_SHA="$(git rev-parse HEAD)"
docker build \ docker build \
-f ./docker/Dockerfile \ -f ${{ matrix.app.dockerfile }} \
--progress=plain \ --progress=plain \
-t "unsend/unsend-$BUILD_PLATFORM:latest" \ -t "unsend/${{ matrix.app.name }}-$BUILD_PLATFORM:latest" \
-t "unsend/unsend-$BUILD_PLATFORM:$GIT_SHA" \ -t "unsend/${{ matrix.app.name }}-$BUILD_PLATFORM:$GIT_SHA" \
-t "unsend/unsend-$BUILD_PLATFORM:$APP_VERSION" \ -t "unsend/${{ matrix.app.name }}-$BUILD_PLATFORM:$APP_VERSION" \
-t "ghcr.io/unsend-dev/unsend-$BUILD_PLATFORM:latest" \ -t "ghcr.io/unsend-dev/${{ matrix.app.name }}-$BUILD_PLATFORM:latest" \
-t "ghcr.io/unsend-dev/unsend-$BUILD_PLATFORM:$GIT_SHA" \ -t "ghcr.io/unsend-dev/${{ matrix.app.name }}-$BUILD_PLATFORM:$GIT_SHA" \
-t "ghcr.io/unsend-dev/unsend-$BUILD_PLATFORM:$APP_VERSION" \ -t "ghcr.io/unsend-dev/${{ matrix.app.name }}-$BUILD_PLATFORM:$APP_VERSION" \
. ${{ matrix.app.context }}
- name: Push the docker image to DockerHub - name: Push the docker image to DockerHub
run: docker push --all-tags "unsend/unsend-$BUILD_PLATFORM" run: docker push --all-tags "unsend/${{ matrix.app.name }}-$BUILD_PLATFORM"
env: env:
BUILD_PLATFORM: ${{ matrix.os == 'warp-ubuntu-latest-arm64-2x' && 'arm64' || 'amd64' }} BUILD_PLATFORM: ${{ matrix.os == 'warp-ubuntu-latest-arm64-2x' && 'arm64' || 'amd64' }}
- name: Push the docker image to GitHub Container Registry - name: Push the docker image to GitHub Container Registry
run: docker push --all-tags "ghcr.io/unsend-dev/unsend-$BUILD_PLATFORM" run: docker push --all-tags "ghcr.io/unsend-dev/${{ matrix.app.name }}-$BUILD_PLATFORM"
env: env:
BUILD_PLATFORM: ${{ matrix.os == 'warp-ubuntu-latest-arm64-2x' && 'arm64' || 'amd64' }} BUILD_PLATFORM: ${{ matrix.os == 'warp-ubuntu-latest-arm64-2x' && 'arm64' || 'amd64' }}
@@ -103,45 +110,49 @@ jobs:
APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')" APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
GIT_SHA="$(git rev-parse HEAD)" GIT_SHA="$(git rev-parse HEAD)"
docker manifest create \ for APP_NAME in unsend smtp-proxy; do
unsend/unsend:latest \ docker manifest create \
--amend unsend/unsend-amd64:latest \ unsend/$APP_NAME:latest \
--amend unsend/unsend-arm64:latest \ --amend unsend/$APP_NAME-amd64:latest \
--amend unsend/$APP_NAME-arm64:latest
docker manifest create \ docker manifest create \
unsend/unsend:$GIT_SHA \ unsend/$APP_NAME:$GIT_SHA \
--amend unsend/unsend-amd64:$GIT_SHA \ --amend unsend/$APP_NAME-amd64:$GIT_SHA \
--amend unsend/unsend-arm64:$GIT_SHA \ --amend unsend/$APP_NAME-arm64:$GIT_SHA
docker manifest create \ docker manifest create \
unsend/unsend:$APP_VERSION \ unsend/$APP_NAME:$APP_VERSION \
--amend unsend/unsend-amd64:$APP_VERSION \ --amend unsend/$APP_NAME-amd64:$APP_VERSION \
--amend unsend/unsend-arm64:$APP_VERSION \ --amend unsend/$APP_NAME-arm64:$APP_VERSION
docker manifest push unsend/unsend:latest docker manifest push unsend/$APP_NAME:latest
docker manifest push unsend/unsend:$GIT_SHA docker manifest push unsend/$APP_NAME:$GIT_SHA
docker manifest push unsend/unsend:$APP_VERSION docker manifest push unsend/$APP_NAME:$APP_VERSION
done
- name: Create and push Github Container Registry manifest - name: Create and push Github Container Registry manifest
run: | run: |
APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')" APP_VERSION="$(git name-rev --tags --name-only $(git rev-parse HEAD) | head -n 1 | sed 's/\^0//')"
GIT_SHA="$(git rev-parse HEAD)" GIT_SHA="$(git rev-parse HEAD)"
docker manifest create \ for APP_NAME in unsend smtp-proxy; do
ghcr.io/unsend-dev/unsend:latest \ docker manifest create \
--amend ghcr.io/unsend-dev/unsend-amd64:latest \ ghcr.io/unsend-dev/$APP_NAME:latest \
--amend ghcr.io/unsend-dev/unsend-arm64:latest \ --amend ghcr.io/unsend-dev/$APP_NAME-amd64:latest \
--amend ghcr.io/unsend-dev/$APP_NAME-arm64:latest
docker manifest create \ docker manifest create \
ghcr.io/unsend-dev/unsend:$GIT_SHA \ ghcr.io/unsend-dev/$APP_NAME:$GIT_SHA \
--amend ghcr.io/unsend-dev/unsend-amd64:$GIT_SHA \ --amend ghcr.io/unsend-dev/$APP_NAME-amd64:$GIT_SHA \
--amend ghcr.io/unsend-dev/unsend-arm64:$GIT_SHA \ --amend ghcr.io/unsend-dev/$APP_NAME-arm64:$GIT_SHA
docker manifest create \ docker manifest create \
ghcr.io/unsend-dev/unsend:$APP_VERSION \ ghcr.io/unsend-dev/$APP_NAME:$APP_VERSION \
--amend ghcr.io/unsend-dev/unsend-amd64:$APP_VERSION \ --amend ghcr.io/unsend-dev/$APP_NAME-amd64:$APP_VERSION \
--amend ghcr.io/unsend-dev/unsend-arm64:$APP_VERSION \ --amend ghcr.io/unsend-dev/$APP_NAME-arm64:$APP_VERSION
docker manifest push ghcr.io/unsend-dev/unsend:latest docker manifest push ghcr.io/unsend-dev/$APP_NAME:latest
docker manifest push ghcr.io/unsend-dev/unsend:$GIT_SHA docker manifest push ghcr.io/unsend-dev/$APP_NAME:$GIT_SHA
docker manifest push ghcr.io/unsend-dev/unsend:$APP_VERSION docker manifest push ghcr.io/unsend-dev/$APP_NAME:$APP_VERSION
done

View File

@@ -0,0 +1,45 @@
# Stage 1: Build stage
FROM node:20-alpine AS builder
# Install pnpm (package manager) globally
RUN npm install -g pnpm
# Set working directory for the application
WORKDIR /app
# Copy configuration files first
COPY package.json tsconfig.json tsup.config.ts ./
# Install dependencies (including devDependencies)
RUN pnpm install
# Copy the source code
COPY src/ ./src/
# Build the application
RUN pnpm run build
# Remove development dependencies to reduce size
RUN pnpm prune --prod
# Stage 2: Production stage
FROM node:20-alpine AS production
# Set working directory in the final image
WORKDIR /app
# Copy necessary files from the builder stage: production node_modules, build output, and package definition
COPY --from=builder /app/node_modules ./node_modules
# Copy only the necessary files from builder
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./package.json
# Expose SMTP ports (standard SMTP, SMTPS, and alternative ports)
EXPOSE 25 465 587 2465 2587
# Run the SMTP server
CMD ["node", "dist/server.js"]

View File

@@ -0,0 +1,29 @@
name: unsend-smtp-server
services:
smtp-server:
container_name: unsend-smtp-server
image: unsend/smtp-proxy:latest
# Pass necessary environment variables
environment:
SMTP_AUTH_USERNAME: "unsend" # can be anything, just use the same while sending emails
UNSEND_BASE_URL: "https://app.unsend.dev" # your self hosted unsend instance url
# Uncomment this if you have SSL certificates. port 465 and 2465 will be using SSL
# UNSEND_API_KEY_PATH: "/certs/server.key"
# UNSEND_API_CERT_PATH: "/certs/server.crt"
# If you have SSL certificates, mount them here (read-only recommended)
# volumes:
# - ./certs/server.key:/certs/server.key:ro
# - ./certs/server.crt:/certs/server.crt:ro
# Expose the SMTP ports
ports:
- "25:25"
- "587:587"
- "2587:2587"
- "465:465"
- "2465:2465"
# Restart always or on-failure, depending on preference
restart: unless-stopped

View File

@@ -81,10 +81,9 @@ const serverOptions: SMTPServerOptions = {
replyTo: parsed.replyTo?.text, replyTo: parsed.replyTo?.text,
}; };
console.log("Parsed email data:", emailObject); // Debug statement
sendEmailToUnsend(emailObject, session.user) sendEmailToUnsend(emailObject, session.user)
.then(() => callback()) .then(() => callback())
.then(() => console.log("Email sent successfully to: ", emailObject.to))
.catch((error) => { .catch((error) => {
console.error("Failed to send email:", error.message); console.error("Failed to send email:", error.message);
callback(error); callback(error);
@@ -104,18 +103,22 @@ const serverOptions: SMTPServerOptions = {
}; };
function startServers() { function startServers() {
// Implicit SSL/TLS for ports 465 and 2465 if (SSL_KEY_PATH && SSL_CERT_PATH) {
[465, 2465].forEach((port) => { // Implicit SSL/TLS for ports 465 and 2465
const server = new SMTPServer({ ...serverOptions, secure: true }); [465, 2465].forEach((port) => {
const server = new SMTPServer({ ...serverOptions, secure: true });
server.listen(port, () => { server.listen(port, () => {
console.log(`Implicit SSL/TLS SMTP server is listening on port ${port}`); console.log(
}); `Implicit SSL/TLS SMTP server is listening on port ${port}`
);
});
server.on("error", (err) => { server.on("error", (err) => {
console.error(`Error occurred on port ${port}:`, err); console.error(`Error occurred on port ${port}:`, err);
});
}); });
}); }
// STARTTLS for ports 25, 587, and 2587 // STARTTLS for ports 25, 587, and 2587
[25, 587, 2587].forEach((port) => { [25, 587, 2587].forEach((port) => {

View File

@@ -1,8 +1,8 @@
const nodemailer = require("nodemailer"); const nodemailer = require("nodemailer");
const transporter = nodemailer.createTransport({ const transporter = nodemailer.createTransport({
host: "smtp.unsend.dev", host: "localhost",
port: 2587, port: 25,
secure: false, secure: false,
auth: { auth: {
user: "unsend", user: "unsend",