Add script for sending test message

This commit is contained in:
2026-08-29 20:29:13 +03:00
parent 784662c967
commit dd6445547b
5 changed files with 72 additions and 4 deletions
+3 -3
View File
@@ -62,11 +62,11 @@ The command prints `SMTP_CONNECTION_OK` only after the SMTP server accepts the S
6. Send a delivery test to an inbox you control:
```powershell
.\scripts\test-smtp.ps1 -To you@example.com
```sh
python ./scripts/send-test-email.py --to you@example.com
```
The command prints `SMTP_TEST_SENT_TO=<address>` only after the SMTP server accepts the message. Confirm the message arrives, then use **Forgot your password?** in the application to verify a real reset email and link.
The command works on Windows, Linux, and macOS. It prints `SMTP_TEST_SENT_TO=<address>` only after the SMTP server accepts the message. Confirm the message arrives, then use **Forgot your password?** in the application to verify a real reset email and link. The existing PowerShell alternative remains available as `./scripts/test-smtp.ps1 -To you@example.com`.
## Production notes
+1 -1
View File
@@ -4,7 +4,7 @@
- [x] Local accounts, administrator approval, and TOTP MFA.
- [x] QR-based MFA enrollment for iPhone and Android authenticators.
- [x] Email addresses, member password changes, and expiring password-reset links.
- [ ] Configure production SMTP credentials and verify outgoing email delivery. Run `python ./scripts/check-smtp.py`, then complete after the delivery test in [README.md](README.md) is received.
- [ ] Configure production SMTP credentials and verify outgoing email delivery. Run `python ./scripts/check-smtp.py`, then `python ./scripts/send-test-email.py --to you@example.com`; complete after the delivery test in [README.md](README.md) is received.
- [ ] Run `./scripts/rotate-admin.ps1` on Windows or `sh ./scripts/rotate-admin.sh` on Linux/macOS, then sign in as `admin` and scan the new MFA QR code to complete authenticator enrollment.
- [x] Add CSRF protection to all state-changing forms.
- [ ] Add automated database backups and test restoration.
Binary file not shown.
Binary file not shown.
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env python3
"""Send one explicit SMTP delivery test email using local .env settings."""
import argparse
import os
import smtplib
import ssl
import sys
from datetime import datetime, timezone
from email.message import EmailMessage
from pathlib import Path
REQUIRED_SETTINGS = ("MAIL_HOST", "MAIL_PORT", "MAIL_USERNAME", "MAIL_PASSWORD", "MAIL_FROM")
def load_dotenv(path):
if not path.is_file():
raise RuntimeError("Missing .env. Copy .env.example to .env and enter the SMTP settings.")
for line in path.read_text(encoding="utf-8").splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
key, separator, value = line.partition("=")
if separator and key.strip():
os.environ.setdefault(key.strip(), value.strip().strip('"').strip("'"))
def main():
parser = argparse.ArgumentParser(description="Send an Eternity Project SMTP test email.")
parser.add_argument("--to", required=True, help="Recipient email address")
args = parser.parse_args()
project_root = Path(__file__).resolve().parent.parent
load_dotenv(project_root / ".env")
missing = [setting for setting in REQUIRED_SETTINGS if not os.environ.get(setting)]
if missing:
raise RuntimeError(f"Missing required SMTP settings: {', '.join(missing)}")
message = EmailMessage()
message["Subject"] = "Eternity Project SMTP verification"
message["From"] = os.environ["MAIL_FROM"]
message["To"] = args.to
message.set_content(
f"SMTP delivery verification completed at {datetime.now(timezone.utc).isoformat()}.\n"
"You can now test password-reset delivery from the application."
)
try:
with smtplib.SMTP(os.environ["MAIL_HOST"], int(os.environ["MAIL_PORT"]), timeout=15) as client:
client.ehlo()
client.starttls(context=ssl.create_default_context())
client.ehlo()
client.login(os.environ["MAIL_USERNAME"], os.environ["MAIL_PASSWORD"])
client.send_message(message)
except (OSError, smtplib.SMTPException) as error:
print(f"SMTP_TEST_FAILED: {error}", file=sys.stderr)
return 1
print(f"SMTP_TEST_SENT_TO={args.to}")
return 0
if __name__ == "__main__":
try:
raise SystemExit(main())
except RuntimeError as error:
print(f"SMTP_CONFIGURATION_ERROR: {error}", file=sys.stderr)
raise SystemExit(2)