A small Go application that reads recipients from a CSV file, renders an HTML/text email template for each recipient, sends the messages through SMTP, and logs delivery results to a local SQLite database.
- Loads recipients from
emails.csv - Renders
email.tmplfor each recipient using Go templates - Sends email through an SMTP server
- Stores send/failure history in SQLite
- Prints a final campaign summary with totals and failed deliveries
main.go- application entry point and worker orchestrationconfig.go- environment-driven configuration loadingconsumer.go- CSV reader that streams recipients into a channelproducer.go- worker logic that renders templates and sends emaildatabase.go- SQLite initialization and logging helpersemail.tmpl- email template used for each recipientemails.csv- sample recipient listinfo.md- extra notes for the project
- The app reads runtime settings from environment variables.
- A SQLite database is created if it does not already exist.
- Recipients are loaded from the CSV file and sent to workers through a channel.
- Each worker renders the template with recipient data.
- The email is sent with
net/smtp. - Successes and failures are written to the
email_logstable. - When all workers finish, the app prints delivery statistics and any failed emails.
- Go 1.25 or newer
- An SMTP server for local testing or real delivery
- SQLite is embedded through the Go dependency, so no separate database server is needed
For local testing, Mailpit is a convenient SMTP sink that accepts messages and exposes a web UI.
docker run -d --restart unless-stopped --name mailpit -p 8025:8025 -p 1025:1025 axllent/mailpitIf localhost resolves to IPv6 on your machine, use 127.0.0.1 for the SMTP host.
Mailpit UI: http://localhost:8025
The app is configured entirely through environment variables. Every value has a default.
| Variable | Default | Purpose |
|---|---|---|
MAILCHIMP_DB_PATH |
mailchimp.db |
Path to the SQLite database file |
MAILCHIMP_EMAILS_CSV |
./emails.csv |
Path to the recipient CSV file |
MAILCHIMP_TEMPLATE_PATH |
email.tmpl |
Path to the email template file |
MAILCHIMP_SMTP_HOST |
127.0.0.1 |
SMTP server host |
MAILCHIMP_SMTP_PORT |
1025 |
SMTP server port |
MAILCHIMP_SENDER_EMAIL |
shreyashukla20042005@gmail.com |
Sender address used in SMTP delivery |
MAILCHIMP_WORKER_COUNT |
5 |
Number of concurrent email workers |
MAILCHIMP_SEND_DELAY_MS |
50 |
Delay between sends per worker in milliseconds |
$env:MAILCHIMP_SMTP_HOST = "127.0.0.1"
$env:MAILCHIMP_SMTP_PORT = "1025"
$env:MAILCHIMP_SENDER_EMAIL = "sender@example.com"
$env:MAILCHIMP_WORKER_COUNT = "5"
$env:MAILCHIMP_SEND_DELAY_MS = "50"export MAILCHIMP_SMTP_HOST=127.0.0.1
export MAILCHIMP_SMTP_PORT=1025
export MAILCHIMP_SENDER_EMAIL=sender@example.com
export MAILCHIMP_WORKER_COUNT=5
export MAILCHIMP_SEND_DELAY_MS=50From the project root:
go run .If you want to point at a different CSV, template, or database file, set the environment variables before running.
The CSV file must include a header row with at least these columns:
nameemail
Example:
name,email
Alice Johnson,alice.johnson@example.com
Bob Smith,bob.smith@example.comThe template is rendered with a Recipient object that exposes Name and Email.
Example:
Subject: Hello, {{.Name}}
Hi {{.Name}}
Thanks,
Shreya
The application creates an email_logs table automatically.
Columns:
email- recipient email addressname- recipient namestatus-sentorfailedfailure_type- failure category such astemplate_errororsmtp_errorerror_msg- error message from the send attemptattempts- retry count recorded by the appsent_at- timestamp for successful sendsfailed_at- timestamp for failed sendscreated_at- row creation timestamp
At the end of a run, the app prints:
- Total rows logged
- Count of sent emails
- Count of failed emails
- A list of failed recipients when failures occurred
- If nothing is sent, confirm the SMTP host and port are reachable.
- If template parsing fails, check that
email.tmplexists and contains valid Go template syntax. - If the CSV fails to load, make sure the first row is a header and the data rows have at least two columns.
- If the database file cannot be created, verify that the working directory is writable.
- If you are testing with Mailpit, open the UI at http://localhost:8025 to inspect received messages.
- The sender address is configurable, but the current default in code is a sample personal address. Override it for real use.
- Failed sends are logged immediately and included in the final summary.
- The worker count and per-send delay make it easy to tune throughput while testing.