Skip to content

Commit 9442de4

Browse files
authored
Merge pull request #4 from Baker/clean-up-tests
ci/cd, tests, documentation and more.
2 parents 4d0d8ef + 6afe688 commit 9442de4

18 files changed

Lines changed: 692 additions & 129 deletions

.github/.testcoverage.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Configuration for vladopajic/go-test-coverage
2+
# Minimal setup to match CI job
3+
profile: '' # set via github action
4+
threshold:
5+
file: 75
6+
total: 75

.github/workflows/ci.yml

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,50 +6,111 @@ on:
66
pull_request:
77
branches: [ main ]
88

9-
permissions:
10-
contents: read
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
permissions: write-all
1114

1215
jobs:
1316
lint:
14-
name: golangci-lint
17+
name: 🧹 golangci-lint
1518
runs-on: ubuntu-latest
1619
steps:
17-
- name: Checkout
20+
- name: 📥 Checkout
1821
uses: actions/checkout@v4
1922

20-
- name: Set up Go
23+
- name: 🔧 Set up Go
2124
uses: actions/setup-go@v5
2225
with:
2326
go-version-file: go.mod
2427
cache: true
2528

26-
- name: Install golangci-lint
29+
- name: 🕵️ Install golangci-lint
2730
uses: golangci/golangci-lint-action@v8
2831
with:
2932
version: v2.3
3033
args: --timeout=5m
3134

35+
- name: 🛡️ Run govulncheck
36+
run: |
37+
go install golang.org/x/vuln/cmd/govulncheck@latest
38+
govulncheck ./...
39+
40+
41+
test:
42+
name: 🧪 Test
43+
needs:
44+
- lint
45+
runs-on: ${{ matrix.os }}
46+
strategy:
47+
fail-fast: false
48+
matrix:
49+
os: [ubuntu-latest, macos-latest, windows-latest]
50+
go: [stable, oldstable]
51+
steps:
52+
- name: 📥 Checkout
53+
uses: actions/checkout@v4
54+
55+
- name: 🔧 Set up Go
56+
uses: actions/setup-go@v5
57+
with:
58+
go-version: ${{ matrix.go }}
59+
cache: true
60+
61+
- name: 🧪 Test
62+
run: go test -v ./...
63+
64+
65+
coverage:
66+
name: 📊 Coverage gate
67+
needs:
68+
- lint
69+
- test
70+
runs-on: ubuntu-latest
71+
steps:
72+
- name: 📥 Checkout
73+
uses: actions/checkout@v4
74+
75+
- name: 🔧 Set up Go
76+
uses: actions/setup-go@v5
77+
with:
78+
go-version: stable
79+
cache: true
80+
81+
- name: 🧪 Run tests with coverage
82+
run: go test -covermode=atomic -coverpkg=./... -coverprofile=cover.out ./...
83+
84+
- name: ✅ Enforce coverage threshold
85+
uses: vladopajic/go-test-coverage@v2
86+
continue-on-error: true
87+
with:
88+
profile: cover.out
89+
config: ./.github/.testcoverage.yml
90+
91+
3292
build:
33-
name: Build matrix
93+
name: 🔨 Build matrix
3494
needs:
3595
- lint
96+
- test
3697
runs-on: ${{ matrix.os }}
3798
strategy:
3899
fail-fast: false
39100
matrix:
40101
os: [ubuntu-latest, macos-latest, windows-latest]
41-
go: [stable]
102+
go: [stable, oldstable]
42103
steps:
43-
- name: Checkout
104+
- name: 📥 Checkout
44105
uses: actions/checkout@v4
45106

46-
- name: Set up Go
107+
- name: 🔧 Set up Go
47108
uses: actions/setup-go@v5
48109
with:
49110
go-version: ${{ matrix.go }}
50111
cache: true
51112

52-
- name: Build
113+
- name: 🔨 Build
53114
shell: bash
54115
run: |
55116
go env

.github/workflows/cleanup-deployments.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ on:
1414
default: "1"
1515
type: string
1616
dry_run:
17-
description: Show what would be deleted without deleting
17+
description: Dry run mode; shows what would be deleted without deleting anything.
1818
required: true
1919
default: "true"
2020
type: choice

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
.env
2+
*.out

.golangci.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,24 @@ linters:
1414
- unused
1515
- gocyclo
1616
- misspell
17+
- gosec
18+
- gocritic
19+
- revive
1720
settings:
1821
gocyclo:
1922
min-complexity: 20
2023
misspell:
2124
locale: US
25+
revive:
26+
rules:
27+
- name: unused-parameter
28+
disabled: true
2229

2330
formatters:
2431
enable:
2532
- gofmt
2633
- goimports
34+
- gofumpt
2735

2836
issues:
2937
max-issues-per-linter: 0

Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ run-dev: build
4242

4343
# Run tests
4444
test:
45-
@echo "Running tests..."
46-
go test -v ./...
45+
@echo "Running tests..."
46+
go test -v ./...
47+
4748

4849
# Clean build artifacts
4950
clean:

README.md

Lines changed: 41 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
# InboundParse - Enhanced Email to Webhook Gateway
1+
# InboundParse - Email to Webhook Gateway
22

33
A modern SMTP server that receives emails from any domain without authentication and forwards them to webhooks with comprehensive email authentication validation and SSL/TLS support.
44

55
## Features
66

7-
- **No Authentication Required**: Accepts emails from any domain without username/password
8-
- **SSL/TLS Support**: Automatic SSL certificate management via Let's Encrypt
7+
- **No SMTP Auth Required**: Accepts emails from any domain without username/password
8+
- **TLS Support**: Optional TLS when `-cert-file` and `-key-file` are provided
99
- **SPF Validation**: Validates Sender Policy Framework records
10-
- **DKIM Validation**: Verifies DomainKeys Identified Mail signatures
11-
- **DMARC Validation**: Checks Domain-based Message Authentication, Reporting & Conformance policies
12-
- **Complete Headers**: Includes all email headers in the webhook payload
10+
- **DKIM Validation**: Verifies DomainKeys Identified Mail signatures
11+
- **DMARC Validation**: Evaluates DMARC policy and alignment
12+
- **Headers Included**: Forwards received headers along with parsed message data
1313
- **Webhook Authentication**: Supports HTTP Basic Auth for webhook endpoints
14-
- **Comprehensive Logging**: Detailed logging with verbose mode option
15-
- **Multiple Ports**: Supports both port 25 (SMTP) and 587 (submission)
14+
- **Verbose Logging**: Enable extra logs with `-verbose`
15+
- **Multiple Ports**: Listens on 25 by default; TLS listener on 587 when certs are provided
16+
- **PROXY protocol**: Accepts PROXY protocol connections (e.g., from load balancers)
1617

1718
## Quick Start
1819

@@ -34,15 +35,17 @@ go build -o inboundparse
3435
```bash
3536
Usage of ./inboundparse:
3637
-listen string
37-
SMTP server listen address (default ":25")
38+
SMTP server listen address (default "0.0.0.0:25")
39+
-listen-tls string
40+
SMTP server listen address for TLS (default "0.0.0.0:587")
3841
-webhook string
3942
Webhook URL to send email data to (required)
4043
-webhook-user string
4144
Basic auth username for webhook
4245
-webhook-pass string
4346
Basic auth password for webhook
4447
-name string
45-
SMTP server name (default "inboundparse")
48+
SMTP server name (default "mx.inboundparse.com")
4649
-max-size int
4750
Maximum message size in bytes (default 10485760)
4851
-read-timeout int
@@ -56,9 +59,9 @@ Usage of ./inboundparse:
5659
-enable-dmarc
5760
Enable DMARC validation (default true)
5861
-cert-file string
59-
SSL certificate file path
62+
TLS certificate file path (optional)
6063
-key-file string
61-
SSL private key file path
64+
TLS private key file path (optional)
6265
-verbose
6366
Enable verbose logging (default false)
6467
```
@@ -71,19 +74,12 @@ You can also configure using environment variables:
7174
- `WEBHOOK_URL` - Webhook URL (required)
7275
- `WEBHOOK_USER` - Basic auth username for webhook
7376
- `WEBHOOK_PASS` - Basic auth password for webhook
74-
- `LISTEN_ADDR` - SMTP server listen address
75-
- `SERVER_NAME` - SMTP server name
77+
- `LISTEN_ADDR` - SMTP server listen address (overrides `-listen`)
78+
- `LISTEN_ADDR_TLS` - TLS server listen address (overrides `-listen-tls`)
7679

77-
#### SSL/TLS Configuration
78-
- `MXDOMAIN` - Domain name for SSL certificates (required for SSL)
79-
- `CERT_FILE` - SSL certificate file path (default: /cert/cert.pem)
80-
- `KEY_FILE` - SSL private key file path (default: /cert/key.pem)
81-
82-
#### Let's Encrypt Configuration
83-
- `CF_Token` - Cloudflare API token for DNS validation
84-
- `CF_Zone_ID` - Cloudflare zone ID
85-
- `DNS_API` - DNS API provider (default: dns_cf)
86-
- `ACME_SH_EMAIL` - Email for Let's Encrypt account registration
80+
#### TLS Configuration
81+
- `CERT_FILE` - TLS certificate file path
82+
- `KEY_FILE` - TLS private key file path
8783

8884
#### Feature Toggles
8985
- `ENABLE_SPF` - Enable SPF validation (default: true)
@@ -93,59 +89,25 @@ You can also configure using environment variables:
9389

9490
## Webhook Payload
9591

96-
The service sends a JSON payload to your webhook with the following structure:
92+
The service sends a JSON payload to your webhook similar to:
9793

9894
```json
9995
{
10096
"timestamp": "2024-01-01T12:00:00Z",
101-
"from": {
102-
"address": "sender@example.com",
103-
"name": "Sender Name"
104-
},
105-
"to": [
106-
{
107-
"address": "recipient1@example.com",
108-
"name": "Recipient 1"
109-
},
110-
{
111-
"address": "recipient2@example.com",
112-
"name": "Recipient 2"
113-
}
114-
],
97+
"from": [{ "address": "sender@example.com", "name": "Sender" }],
98+
"to": [{ "address": "recipient@example.com", "name": "Recipient" }],
11599
"subject": "Email Subject",
116100
"message_id": "<unique-message-id@example.com>",
117-
"headers": {
118-
"From": ["sender@example.com"],
119-
"To": ["recipient1@example.com", "recipient2@example.com"],
120-
"Subject": ["Email Subject"],
121-
"Date": ["Mon, 1 Jan 2024 12:00:00 +0000"],
122-
"Message-ID": ["<unique-message-id@example.com>"],
123-
"Content-Type": ["text/plain; charset=utf-8"]
124-
},
125-
"text_body": "Plain text email body content",
126-
"html_body": "HTML email body content",
101+
"headers": { "From": ["sender@example.com"], "Subject": ["Email Subject"] },
102+
"text_body": "Plain text body",
103+
"enriched_text_body": "...",
104+
"html_body": "<p>HTML body</p>",
105+
"attachments": [ /* array of files */ ],
106+
"inline_files": [ /* array of inline files */ ],
127107
"authentication_results": {
128-
"spf": {
129-
"result": "pass",
130-
"raw": "SPF result: pass for domain example.com from IP 192.168.1.100",
131-
"mechanism": "include:_spf.example.com"
132-
},
133-
"dkim": {
134-
"valid": true,
135-
"signatures": ["Valid: example.com"],
136-
"raw": "DKIM verification found 1 signatures"
137-
},
138-
"dmarc": {
139-
"result": "pass",
140-
"raw": "DMARC record found for domain example.com",
141-
"policy": "quarantine"
142-
}
143-
},
144-
"raw": "Full raw email message including headers and body",
145-
"server_info": {
146-
"remote_addr": "192.168.1.100:54321",
147-
"local_addr": "0.0.0.0:25",
148-
"server_name": "inboundparse"
108+
"spf": { "result": "pass", "raw": "...", "mechanism": "..." },
109+
"dkim": { "valid": true, "signatures": ["Valid: example.com"], "raw": "..." },
110+
"dmarc": { "result": "pass", "raw": "...", "policy": "reject" }
149111
}
150112
}
151113
```
@@ -185,41 +147,26 @@ docker run -p 25:25 -p 587:587 inboundparse \
185147
-verbose=true
186148
```
187149

188-
### Run with Docker (SSL/TLS)
150+
### Run with Docker (TLS)
189151

190-
```bash
191-
docker run -p 25:25 -p 587:587 \
192-
-e WEBHOOK_URL=https://your-webhook-url.com/api/webhook \
193-
-e MXDOMAIN=mx.yourdomain.com \
194-
-e CF_Token=your-cloudflare-token \
195-
-e CF_Zone_ID=your-zone-id \
196-
-e ACME_SH_EMAIL=your-email@example.com \
197-
-e VERBOSE=true \
198-
inboundparse
199-
```
152+
Provide your own certificate and key inside the container and set `CERT_FILE`/`KEY_FILE`.
200153

201154
### Environment File (.env)
202155

203-
Create a `.env` file in your project directory:
156+
Create a `.env` file in your project directory (optional):
204157

205158
```bash
206-
# Required
207159
WEBHOOK_URL=https://your-webhook-url.com/api/webhook
208-
MXDOMAIN=mx.yourdomain.com
209-
210-
# Cloudflare DNS API (required for SSL)
211-
CF_Token=your-cloudflare-token
212-
CF_Zone_ID=your-zone-id
213-
DNS_API=dns_cf
214-
215-
# SSL Configuration
216-
ACME_SH_EMAIL=your-email@example.com
217160

218-
# Feature Configuration
161+
# Optional overrides
162+
LISTEN_ADDR=0.0.0.0:25
163+
LISTEN_ADDR_TLS=0.0.0.0:587
219164
ENABLE_SPF=true
220165
ENABLE_DKIM=true
221166
ENABLE_DMARC=true
222-
VERBOSE=true
167+
VERBOSE=false
168+
CERT_FILE=/cert/cert.pem
169+
KEY_FILE=/cert/key.pem
223170
```
224171

225172
## Testing

0 commit comments

Comments
 (0)