mirror of
https://github.com/DeNNiiInc/Advanced-Smtp-Tester.git
synced 2026-04-18 01:45:58 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a0a903009d | |||
| 158d774731 | |||
| 51c2d4378b | |||
| 592f82d73e | |||
| 128a5d16b1 | |||
| fafab6895b | |||
| 719096be79 | |||
| d6cf8f6603 | |||
| 8dcbacf0ed | |||
| 3801c87230 | |||
| 60f922b2a9 | |||
| 5ee7a469d9 | |||
| 7f204426ed | |||
| 02222026ef | |||
|
|
65bc45f935 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,3 +3,7 @@ dist
|
||||
.DS_Store
|
||||
*.log
|
||||
.env
|
||||
deploy-secrets.json
|
||||
config/secrets.env
|
||||
scripts/auth.json
|
||||
*.zip
|
||||
|
||||
77
PROXMOX_DEPLOY_TEMPLATE.md
Normal file
77
PROXMOX_DEPLOY_TEMPLATE.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# 🚀 Proxmox Deployment Automation (TurnKey Node.js)
|
||||
|
||||
**Use this guide to deploy your project to a TurnKey Linux LXC Container.**
|
||||
|
||||
This project uses an **automated deployment system** that handles:
|
||||
- Initial server setup (Dependencies, Nginx, PM2, Cron).
|
||||
- Automatic updates via Git (Every 5 minutes).
|
||||
- Seamess updates using PM2.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Prerequisites
|
||||
|
||||
1. **Server**: A Proxmox TurnKey Node.js Container.
|
||||
2. **Access**: Root SSH password for the container.
|
||||
3. **Local Files**: Ensure you have `deploy-secrets.json` created (see below).
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Step 1: Configure Secrets
|
||||
|
||||
Create a file named `deploy-secrets.json` in the project root. **This file is gitignored** and safe to store locally.
|
||||
|
||||
```json
|
||||
{
|
||||
"host": "172.16.69.217",
|
||||
"username": "root",
|
||||
"password": "YOUR_SSH_PASSWORD",
|
||||
"gitUser": "YOUR_GITHUB_EMAIL",
|
||||
"gitToken": "YOUR_GITHUB_TOKEN",
|
||||
"repoUrl": "https://github.com/YOUR_ORG/YOUR_REPO.git"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Step 2: Run Deployment
|
||||
|
||||
Open PowerShell in the project root and run:
|
||||
|
||||
```powershell
|
||||
./deploy-to-proxmox.ps1
|
||||
```
|
||||
|
||||
**That's it!** The script will:
|
||||
1. Connect to your server.
|
||||
2. Clone the repository using your token.
|
||||
3. Install all dependencies (Git, Nginx, PM2).
|
||||
4. Configure Nginx as a reverse proxy (Port 80 -> 4001).
|
||||
5. Set up a Cron job to auto-sync changes every 5 minutes.
|
||||
|
||||
---
|
||||
|
||||
## 🔄 How Updates Work
|
||||
|
||||
The server runs a cron job (`scripts/sync-and-restart.sh`) every 5 minutes that:
|
||||
1. Checks GitHub for changes.
|
||||
2. If changes are found:
|
||||
- Pulls the new code.
|
||||
- Installs dependencies (if `package.json` changed).
|
||||
- Restarts the application via PM2.
|
||||
|
||||
To update your live site, simply **Push to GitHub** and wait ~5 minutes.
|
||||
|
||||
---
|
||||
|
||||
## <20> Troubleshooting
|
||||
|
||||
**View Logs:**
|
||||
```bash
|
||||
ssh root@<SERVER_IP> "cat /var/log/smtp-tester-sync.log"
|
||||
```
|
||||
|
||||
**Manual Update:**
|
||||
```bash
|
||||
ssh root@<SERVER_IP> "/var/www/Advanced-Smtp-Tester/scripts/sync-and-restart.sh"
|
||||
```
|
||||
227
README.md
227
README.md
@@ -1,124 +1,175 @@
|
||||
# Advanced SMTP Tester
|
||||
# 📧 Advanced SMTP Tester
|
||||
|
||||
A powerful desktop application for testing SMTP configurations with support for multiple providers, dark mode, test history, and enhanced error messages.
|
||||

|
||||
|
||||
## Features
|
||||
**A professional, feature-rich SMTP testing utility for developers and system administrators.**
|
||||
|
||||
### 🎨 User Interface
|
||||
- **Dark/Light Mode** - Toggle between themes with persistence
|
||||
- **Configuration Presets** - Quick-load for Office 365, Gmail, SendGrid, Mailgun, Amazon SES
|
||||
- **Test History** - Last 50 tests with click-to-load
|
||||
- **Enhanced Errors** - Helpful troubleshooting tips for common issues
|
||||
Test SMTP configurations, troubleshoot connection issues, and validate email delivery with an elegant, intuitive interface.
|
||||
|
||||
### 🖥️ Desktop Application
|
||||
- **Native Windows App** - Runs in its own window (no browser needed)
|
||||
- **System Tray** - Minimize to tray, quick access
|
||||
- **Menu Bar** - Full application menu
|
||||
- **Auto-Start Server** - Express server starts automatically
|
||||
<div align="center">
|
||||
|
||||
### 📧 SMTP Testing
|
||||
- **Multiple Encryption** - STARTTLS, SSL/TLS, Unencrypted
|
||||
- **Auto-Discovery** - Test multiple port/encryption combinations
|
||||
- **Beautiful Emails** - Professional HTML test emails
|
||||
- **Detailed Results** - Full response logs and error messages
|
||||
[](https://advanced-smtp-tester.beyondcloud.technology/)
|
||||
[](https://github.com/DeNNiiInc/Advanced-Smtp-Tester)
|
||||
[](LICENSE)
|
||||
|
||||
## Installation
|
||||
</div>
|
||||
|
||||
### Desktop App (Windows)
|
||||
1. Download the latest release from [Releases](https://github.com/DeNNiiInc/Advanced-Smtp-Tester/releases)
|
||||
2. Extract the ZIP file
|
||||
3. Run `Advanced-SMTP-Tester.exe`
|
||||
---
|
||||
|
||||
## 🌐 Live Demo
|
||||
|
||||
**Try it now:** [https://advanced-smtp-tester.beyondcloud.technology/](https://advanced-smtp-tester.beyondcloud.technology/)
|
||||
|
||||
---
|
||||
|
||||
## 📸 Screenshots
|
||||
|
||||
### Desktop View (1920x1080)
|
||||

|
||||
|
||||
### Mobile View
|
||||

|
||||
|
||||
---
|
||||
|
||||
## ✨ Key Features
|
||||
|
||||
### 🎨 **Premium User Experience**
|
||||
- **Dark/Light Mode** - Seamless theme switching with persistence
|
||||
- **Glassmorphism Design** - Modern, polished interface with smooth animations
|
||||
- **Fully Responsive** - Perfect experience on desktop, tablet, and mobile devices
|
||||
- **Git Version Badge** - Always know what version is deployed (bottom-right corner)
|
||||
|
||||
### ⚡ **Powerful Testing Capabilities**
|
||||
- **Quick Presets** - Pre-configured settings for popular providers:
|
||||
- Microsoft Office 365
|
||||
- Google Gmail
|
||||
- SendGrid
|
||||
- Mailgun
|
||||
- Amazon SES
|
||||
- **Auto-Discovery** - Automatically test multiple port/encryption combinations:
|
||||
- Ports: 25, 465, 587, 2525
|
||||
- Encryption: SSL/TLS, STARTTLS, Unencrypted
|
||||
- **Enhanced Error Handling** - Intelligent error analysis with actionable troubleshooting tips
|
||||
|
||||
### 📊 **History & Insights**
|
||||
- **Local Test History** - Automatically saves recent tests in browser storage
|
||||
- **Detailed Logs** - View complete SMTP transaction logs and server responses
|
||||
- **Click-to-Reload** - Quickly retest previous configurations
|
||||
|
||||
### 🔒 **Security & Privacy**
|
||||
- **No Server Storage** - Credentials are processed in-memory only
|
||||
- **Browser-Only History** - Test history stored locally (IndexedDB)
|
||||
- **Clear Warning** - Password inclusion in test emails is clearly indicated
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Installation Options
|
||||
|
||||
### Option 1: Use the Live Demo ✨ **Recommended**
|
||||
|
||||
No installation needed! Just visit:
|
||||
**[https://advanced-smtp-tester.beyondcloud.technology/](https://advanced-smtp-tester.beyondcloud.technology/)**
|
||||
|
||||
### Option 2: Run Locally (Node.js)
|
||||
|
||||
### Web Version
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/DeNNiiInc/Advanced-Smtp-Tester.git
|
||||
cd Advanced-Smtp-Tester
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Start the server
|
||||
npm start
|
||||
```
|
||||
Open `http://localhost:3000` in your browser.
|
||||
|
||||
### Electron Development
|
||||
# Access at http://localhost:3000
|
||||
```
|
||||
|
||||
### Option 3: Desktop App (Electron)
|
||||
|
||||
```bash
|
||||
npm install
|
||||
# Development mode
|
||||
npm run electron
|
||||
```
|
||||
|
||||
## Building from Source
|
||||
|
||||
### Web Version
|
||||
```bash
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
### Desktop App
|
||||
```bash
|
||||
npm install
|
||||
# Build Windows installer
|
||||
npm run build
|
||||
```
|
||||
|
||||
Or use electron-packager:
|
||||
```bash
|
||||
npx electron-packager . "Advanced-SMTP-Tester" --platform=win32 --arch=x64 --out=dist --overwrite
|
||||
```
|
||||
### Option 4: Automated Proxmox Deployment
|
||||
|
||||
## Usage
|
||||
For automated deployment to **TurnKey Linux Node.js** containers:
|
||||
|
||||
1. Create `deploy-secrets.json` (see `PROXMOX_DEPLOY_TEMPLATE.md`)
|
||||
2. Run: `./deploy-to-proxmox.ps1`
|
||||
|
||||
Features automatic:
|
||||
- Dependency installation (Git, Nginx, PM2, Cloudflared)
|
||||
- Nginx reverse proxy configuration
|
||||
- Auto-updates every 5 minutes via cron
|
||||
|
||||
📖 **[Full Deployment Guide](PROXMOX_DEPLOY_TEMPLATE.md)**
|
||||
|
||||
---
|
||||
|
||||
## 💡 Usage
|
||||
|
||||
### Quick Start
|
||||
1. Select a preset (e.g., "Microsoft Office 365")
|
||||
2. Enter your credentials
|
||||
3. Enter recipient email
|
||||
4. Click "Test Configuration & Send Email"
|
||||
1. Visit [https://advanced-smtp-tester.beyondcloud.technology/](https://advanced-smtp-tester.beyondcloud.technology/)
|
||||
2. Select a preset (e.g., "Microsoft Office 365")
|
||||
3. Enter your credentials
|
||||
4. Enter recipient email address
|
||||
5. Click **"Test Configuration & Send Email"**
|
||||
|
||||
### Auto-Discovery Mode
|
||||
Click **"Auto Discovery Test"** to automatically test all common port and encryption combinations. Successful configurations will send separate test emails.
|
||||
|
||||
### Configuration Presets
|
||||
- **Office 365**: `smtp.office365.com:587` (STARTTLS)
|
||||
- **Gmail**: `smtp.gmail.com:587` (STARTTLS)
|
||||
- **SendGrid**: `smtp.sendgrid.net:587` (STARTTLS)
|
||||
- **Mailgun**: `smtp.mailgun.org:587` (STARTTLS)
|
||||
- **Amazon SES**: `email-smtp.us-east-1.amazonaws.com:587` (STARTTLS)
|
||||
|
||||
### Auto-Discovery
|
||||
Click "Auto Discovery Test" to automatically test multiple port/encryption combinations.
|
||||
| Provider | Host | Port | Encryption |
|
||||
|----------|------|------|------------|
|
||||
| **Office 365** | smtp.office365.com | 587 | STARTTLS |
|
||||
| **Gmail** | smtp.gmail.com | 587 | STARTTLS |
|
||||
| **SendGrid** | smtp.sendgrid.net | 587 | STARTTLS |
|
||||
| **Mailgun** | smtp.mailgun.org | 587 | STARTTLS |
|
||||
| **Amazon SES** | email-smtp.us-east-1.amazonaws.com | 587 | STARTTLS |
|
||||
| **Mail Assure** | smtpout.mtaroutes.com | 587 | STARTTLS |
|
||||
|
||||
## Development
|
||||
---
|
||||
|
||||
### Project Structure
|
||||
```
|
||||
Advanced-Smtp-Tester/
|
||||
├── electron-main.js # Electron entry point
|
||||
├── server.js # Express server
|
||||
├── index.html # Main UI
|
||||
├── public/
|
||||
│ ├── db.js # IndexedDB wrapper
|
||||
│ ├── script.js # Frontend logic
|
||||
│ ├── styles.css # Styling
|
||||
│ └── Logo.png # App icon
|
||||
└── .github/
|
||||
└── workflows/
|
||||
└── build-desktop.yml # Automated builds
|
||||
```
|
||||
|
||||
### Scripts
|
||||
- `npm start` - Start web server
|
||||
- `npm run electron` - Run desktop app
|
||||
- `npm run build` - Build Windows installer
|
||||
- `npm run build:dir` - Build unpacked directory
|
||||
|
||||
## Technologies
|
||||
## 🛠️ Technology Stack
|
||||
|
||||
- **Backend**: Node.js, Express, Nodemailer
|
||||
- **Frontend**: Vanilla JavaScript, IndexedDB
|
||||
- **Desktop**: Electron
|
||||
- **Build**: electron-builder, electron-packager
|
||||
- **Deployment**: PM2, Nginx, Git Auto-Sync
|
||||
- **Design**: Glassmorphism, CSS Variables, Responsive Grid
|
||||
|
||||
## License
|
||||
---
|
||||
|
||||
ISC
|
||||
## 🤝 Contributing
|
||||
|
||||
## Author
|
||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||
|
||||
Beyond Cloud Technology
|
||||
1. Fork the repository
|
||||
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
|
||||
3. Commit your changes (`git commit -m 'Add AmazingFeature'`)
|
||||
4. Push to branch (`git push origin feature/AmazingFeature`)
|
||||
5. Open a Pull Request
|
||||
|
||||
## Links
|
||||
---
|
||||
|
||||
- [GitHub Repository](https://github.com/DeNNiiInc/Advanced-Smtp-Tester)
|
||||
- [YouTube Channel](https://www.youtube.com/@beyondcloudtechnology)
|
||||
## 📄 License
|
||||
|
||||
This project is licensed under the ISC License.
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
|
||||
**Built with ❤️ by Beyond Cloud Technology**
|
||||
|
||||
[YouTube](https://www.youtube.com/@beyondcloudtechnology) • [Website](https://beyondcloud.technology) • [GitHub](https://github.com/DeNNiiInc/Advanced-Smtp-Tester)
|
||||
|
||||
</div>
|
||||
|
||||
44
RELEASE-NOTES.md
Normal file
44
RELEASE-NOTES.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Creating GitHub Release
|
||||
|
||||
The v1.0.0 tag has been pushed to GitHub. The GitHub Actions workflow will automatically:
|
||||
|
||||
1. Build the Windows executable
|
||||
2. Create a release
|
||||
3. Upload the built files
|
||||
|
||||
## What Happened
|
||||
|
||||
✅ **Created ZIP:** `Advanced-SMTP-Tester-v1.0.0-Windows.zip` (137MB)
|
||||
✅ **Created Tag:** `v1.0.0`
|
||||
✅ **Pushed Tag:** Tag is now on GitHub
|
||||
|
||||
## GitHub Actions Status
|
||||
|
||||
The workflow `.github/workflows/build-desktop.yml` will:
|
||||
- Detect the new tag `v1.0.0`
|
||||
- Build the Windows app
|
||||
- Create a GitHub Release
|
||||
- Upload the installer/portable files
|
||||
|
||||
## Check Release Status
|
||||
|
||||
Visit: https://github.com/DeNNiiInc/Advanced-Smtp-Tester/releases
|
||||
|
||||
The release should appear within a few minutes as GitHub Actions completes the build.
|
||||
|
||||
## Manual Upload (If Needed)
|
||||
|
||||
If the automated release doesn't work, you can manually create a release:
|
||||
|
||||
1. Go to: https://github.com/DeNNiiInc/Advanced-Smtp-Tester/releases/new
|
||||
2. Select tag: `v1.0.0`
|
||||
3. Title: `Advanced SMTP Tester v1.0.0`
|
||||
4. Upload: `Advanced-SMTP-Tester-v1.0.0-Windows.zip`
|
||||
5. Click "Publish release"
|
||||
|
||||
## Local ZIP File
|
||||
|
||||
The packaged app is ready at:
|
||||
`Advanced-SMTP-Tester-v1.0.0-Windows.zip` (137MB)
|
||||
|
||||
You can manually upload this to GitHub Releases if needed.
|
||||
25
config/nginx.conf.template
Normal file
25
config/nginx.conf.template
Normal file
@@ -0,0 +1,25 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /var/www/Advanced-Smtp-Tester;
|
||||
index index.html;
|
||||
|
||||
# Serve static frontend files
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# Proxy API requests to Node.js app
|
||||
location /api {
|
||||
proxy_pass http://localhost:4001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# Increase body size for larger payloads if needed
|
||||
client_max_body_size 10M;
|
||||
}
|
||||
75
deploy-to-proxmox.ps1
Normal file
75
deploy-to-proxmox.ps1
Normal file
@@ -0,0 +1,75 @@
|
||||
# deploy-to-proxmox.ps1
|
||||
|
||||
# 1. Read Configuration
|
||||
if (-not (Test-Path "deploy-secrets.json")) {
|
||||
Write-Error "Could not find deploy-secrets.json. Please create it first."
|
||||
exit 1
|
||||
}
|
||||
|
||||
$Config = Get-Content "deploy-secrets.json" | ConvertFrom-Json
|
||||
$HostName = $Config.host
|
||||
$User = $Config.username
|
||||
$Password = $Config.password
|
||||
$GitUser = $Config.gitUser
|
||||
$GitToken = $Config.gitToken
|
||||
$RepoUrl = $Config.repoUrl
|
||||
|
||||
# Construct Authenticated Repo URL
|
||||
# Extract the domain and path from RepoUrl (remove https://)
|
||||
$RepoPath = $RepoUrl -replace "https://", ""
|
||||
# Use Token as username (GitHub supports this) to avoid issues with @ in email usernames
|
||||
$AuthRepoUrl = "https://${GitToken}@${RepoPath}"
|
||||
|
||||
$AppName = "Advanced-Smtp-Tester"
|
||||
$RemoteDir = "/var/www/$AppName"
|
||||
|
||||
Write-Host "🚀 Starting Deployment to $HostName..." -ForegroundColor Cyan
|
||||
|
||||
# 2. Define Remote Commands
|
||||
# We use a Here-String for the remote script
|
||||
$RemoteScript = @"
|
||||
set -e
|
||||
|
||||
echo "🔹 [Remote] Checking prerequisites..."
|
||||
if ! command -v git &> /dev/null; then
|
||||
echo "📦 [Remote] Installing Git..."
|
||||
apt-get update && apt-get install -y git
|
||||
fi
|
||||
|
||||
echo "🔹 [Remote] Preparing directory $RemoteDir..."
|
||||
mkdir -p "$RemoteDir"
|
||||
|
||||
# Check if .git exists, if not clone, else pull
|
||||
if [ ! -d "$RemoteDir/.git" ]; then
|
||||
echo "⬇️ [Remote] Cloning repository..."
|
||||
# Clone with token for future auth-less pulls
|
||||
git clone "$AuthRepoUrl" "$RemoteDir"
|
||||
else
|
||||
echo "⬇️ [Remote] Repository exists. Pulling latest..."
|
||||
cd "$RemoteDir"
|
||||
# Update remote url to ensure token is correct (in case it changed)
|
||||
git remote set-url origin "$AuthRepoUrl"
|
||||
git pull
|
||||
fi
|
||||
|
||||
# Run the setup script from the repo
|
||||
echo "⚡ [Remote] Running setup script..."
|
||||
cd "$RemoteDir"
|
||||
chmod +x scripts/setup-server.sh
|
||||
./scripts/setup-server.sh
|
||||
|
||||
echo "✅ [Remote] Deployment Logic Finished."
|
||||
"@ -replace "`r`n", "`n"
|
||||
|
||||
# 3. Execute via Plink (Putty Link) or SSH
|
||||
# We'll use plink if available because it handles password via argument easier than OpenSSH on Windows
|
||||
# If plink is not found, we warn the user.
|
||||
if (Get-Command plink -ErrorAction SilentlyContinue) {
|
||||
echo y | plink -ssh -l $User -pw $Password $HostName $RemoteScript
|
||||
}
|
||||
else {
|
||||
Write-Warning "Plink not found. Trying standard ssh (you may be prompted for password)."
|
||||
ssh "$User@$HostName" $RemoteScript
|
||||
}
|
||||
|
||||
Write-Host "✨ Deployment script completed." -ForegroundColor Green
|
||||
BIN
docs/feature_git_badge.png
Normal file
BIN
docs/feature_git_badge.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
docs/feature_main_interface.png
Normal file
BIN
docs/feature_main_interface.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 144 KiB |
BIN
docs/screenshot_desktop.png
Normal file
BIN
docs/screenshot_desktop.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 464 KiB |
BIN
docs/screenshot_mobile.png
Normal file
BIN
docs/screenshot_mobile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
14
ecosystem.config.js
Normal file
14
ecosystem.config.js
Normal file
@@ -0,0 +1,14 @@
|
||||
module.exports = {
|
||||
apps: [{
|
||||
name: "Advanced-Smtp-Tester",
|
||||
script: "server.js",
|
||||
instances: 1,
|
||||
autorestart: true,
|
||||
watch: false,
|
||||
max_memory_restart: '1G',
|
||||
env: {
|
||||
NODE_ENV: "production",
|
||||
PORT: 4001
|
||||
}
|
||||
}]
|
||||
};
|
||||
101
index.html
101
index.html
@@ -1,10 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="description" content="Advanced SMTP Tester - Test your SMTP configurations securely and easily." />
|
||||
<meta
|
||||
name="description"
|
||||
content="Advanced SMTP Tester - Test your SMTP configurations securely and easily."
|
||||
/>
|
||||
<title>Advanced SMTP Tester</title>
|
||||
<link rel="icon" type="image/png" href="public/Logo.png" />
|
||||
<link rel="stylesheet" href="public/styles.css" />
|
||||
@@ -14,7 +16,8 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap"
|
||||
rel="stylesheet" />
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -36,11 +39,16 @@
|
||||
<p class="subtitle">
|
||||
Advanced SMTP Configuration & Delivery Testing Utility
|
||||
</p>
|
||||
<a href="https://www.youtube.com/@beyondcloudtechnology" target="_blank" rel="noopener noreferrer"
|
||||
class="youtube-link">
|
||||
<a
|
||||
href="https://www.youtube.com/@beyondcloudtechnology"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="youtube-link"
|
||||
>
|
||||
<svg class="youtube-icon" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z" />
|
||||
d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"
|
||||
/>
|
||||
</svg>
|
||||
Watch on YouTube @beyondcloudtechnology
|
||||
</a>
|
||||
@@ -66,6 +74,7 @@
|
||||
<option value="sendgrid">SendGrid</option>
|
||||
<option value="mailgun">Mailgun</option>
|
||||
<option value="amazonses">Amazon SES</option>
|
||||
<option value="mailassure">Mail Assure</option>
|
||||
<option value="custom">💾 Last Used Configuration</option>
|
||||
</select>
|
||||
</div>
|
||||
@@ -74,11 +83,23 @@
|
||||
<!-- Server Details -->
|
||||
<div class="form-group">
|
||||
<label for="host">SMTP Host</label>
|
||||
<input type="text" id="host" name="host" placeholder="smtp.example.com" required />
|
||||
<input
|
||||
type="text"
|
||||
id="host"
|
||||
name="host"
|
||||
placeholder="smtp.example.com"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="port">Port</label>
|
||||
<input type="number" id="port" name="port" placeholder="587" required />
|
||||
<input
|
||||
type="number"
|
||||
id="port"
|
||||
name="port"
|
||||
placeholder="587"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="secure">Encryption</label>
|
||||
@@ -92,13 +113,29 @@
|
||||
<!-- Auth Details -->
|
||||
<div class="form-group">
|
||||
<label for="user">Username / Email</label>
|
||||
<input type="text" id="user" name="user" placeholder="user@example.com" required />
|
||||
<input
|
||||
type="text"
|
||||
id="user"
|
||||
name="user"
|
||||
placeholder="user@example.com"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="pass">Password</label>
|
||||
<div class="password-input-wrapper">
|
||||
<input type="password" id="pass" name="pass" placeholder="••••••••" required />
|
||||
<button type="button" class="toggle-password" onclick="togglePassword()">
|
||||
<input
|
||||
type="password"
|
||||
id="pass"
|
||||
name="pass"
|
||||
placeholder="••••••••"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="toggle-password"
|
||||
onclick="togglePassword()"
|
||||
>
|
||||
👁️
|
||||
</button>
|
||||
</div>
|
||||
@@ -107,11 +144,22 @@
|
||||
<!-- Email Details -->
|
||||
<div class="form-group">
|
||||
<label for="from">From Address (Optional)</label>
|
||||
<input type="email" id="from" name="from" placeholder="Defaults to Username" />
|
||||
<input
|
||||
type="email"
|
||||
id="from"
|
||||
name="from"
|
||||
placeholder="Defaults to Username"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="to">To Address</label>
|
||||
<input type="email" id="to" name="to" placeholder="recipient@example.com" required />
|
||||
<input
|
||||
type="email"
|
||||
id="to"
|
||||
name="to"
|
||||
placeholder="recipient@example.com"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -147,10 +195,14 @@
|
||||
<div class="history-panel" id="historyPanel">
|
||||
<div class="history-header">
|
||||
<h3>📋 Test History</h3>
|
||||
<button class="clear-history-btn" id="clearHistoryBtn">Clear All</button>
|
||||
<button class="clear-history-btn" id="clearHistoryBtn">
|
||||
Clear All
|
||||
</button>
|
||||
</div>
|
||||
<div id="historyList">
|
||||
<div class="history-empty">No test history yet. Run a test to see it here!</div>
|
||||
<div class="history-empty">
|
||||
No test history yet. Run a test to see it here!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -159,19 +211,30 @@
|
||||
<!-- Footer -->
|
||||
<footer class="footer">
|
||||
<p>© 2025 Beyond Cloud Technology. All rights reserved.</p>
|
||||
<a href="https://github.com/DeNNiiInc/Advanced-Smtp-Tester" target="_blank" rel="noopener noreferrer"
|
||||
class="github-link">
|
||||
<a
|
||||
href="https://github.com/DeNNiiInc/Advanced-Smtp-Tester"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="github-link"
|
||||
>
|
||||
<svg class="github-icon" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z" />
|
||||
d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"
|
||||
/>
|
||||
</svg>
|
||||
View on GitHub
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<!-- Version Badge -->
|
||||
<div id="versionBadge" class="version-badge hidden">
|
||||
<span class="commit-hash"></span>
|
||||
<span class="commit-sep">•</span>
|
||||
<span class="commit-date"></span>
|
||||
</div>
|
||||
|
||||
<script src="public/db.js"></script>
|
||||
<script src="public/script.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -34,6 +34,12 @@ const PRESETS = {
|
||||
port: '587',
|
||||
secure: 'false',
|
||||
name: 'Amazon SES'
|
||||
},
|
||||
mailassure: {
|
||||
host: 'smtpout.mtaroutes.com',
|
||||
port: '587',
|
||||
secure: 'false',
|
||||
name: 'Mail Assure'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -233,6 +239,19 @@ function displayErrorWithTips(errorMessage, container) {
|
||||
container.innerHTML = errorMessage + tipsHTML;
|
||||
}
|
||||
|
||||
// ===================================
|
||||
// AUTO-TRIM INPUT FIELDS
|
||||
// ===================================
|
||||
// Automatically trim whitespace from all text inputs on blur
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const textInputs = document.querySelectorAll('input[type="text"], input[type="email"], input[type="password"]');
|
||||
textInputs.forEach(input => {
|
||||
input.addEventListener('blur', function() {
|
||||
this.value = this.value.trim();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ===================================
|
||||
// PASSWORD TOGGLE
|
||||
// ===================================
|
||||
@@ -469,6 +488,50 @@ document.getElementById('autoTestBtn').addEventListener('click', async function
|
||||
}
|
||||
});
|
||||
|
||||
// ===================================
|
||||
// VERSION INFO
|
||||
// ===================================
|
||||
async function loadVersionInfo() {
|
||||
try {
|
||||
const response = await fetch('/api/version');
|
||||
const data = await response.json();
|
||||
|
||||
if (data.hash && data.hash !== 'Unknown') {
|
||||
const badge = document.getElementById('versionBadge');
|
||||
const hashSpan = badge.querySelector('.commit-hash');
|
||||
const dateSpan = badge.querySelector('.commit-date');
|
||||
|
||||
hashSpan.textContent = data.hash; // e.g., 9f3a914
|
||||
dateSpan.textContent = timeAgo(new Date(data.date)); // e.g., 3d ago
|
||||
|
||||
badge.classList.remove('hidden');
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to load version info:', e);
|
||||
}
|
||||
}
|
||||
|
||||
function timeAgo(date) {
|
||||
const seconds = Math.floor((new Date() - date) / 1000);
|
||||
|
||||
let interval = seconds / 31536000;
|
||||
if (interval > 1) return Math.floor(interval) + "y ago";
|
||||
|
||||
interval = seconds / 2592000;
|
||||
if (interval > 1) return Math.floor(interval) + "mo ago";
|
||||
|
||||
interval = seconds / 86400;
|
||||
if (interval > 1) return Math.floor(interval) + "d ago";
|
||||
|
||||
interval = seconds / 3600;
|
||||
if (interval > 1) return Math.floor(interval) + "h ago";
|
||||
|
||||
interval = seconds / 60;
|
||||
if (interval > 1) return Math.floor(interval) + "m ago";
|
||||
|
||||
return Math.floor(seconds) + "s ago";
|
||||
}
|
||||
|
||||
// ===================================
|
||||
// INITIALIZATION
|
||||
// ===================================
|
||||
@@ -482,6 +545,9 @@ window.addEventListener('DOMContentLoaded', async () => {
|
||||
// Load history
|
||||
await loadHistory();
|
||||
|
||||
// Load Version Info
|
||||
await loadVersionInfo();
|
||||
|
||||
// Load last used configuration
|
||||
const settings = await window.smtpDB.getSettings();
|
||||
if (settings) {
|
||||
|
||||
@@ -77,12 +77,12 @@ body {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: radial-gradient(circle at 15% 50%,
|
||||
background: radial-gradient(
|
||||
circle at 15% 50%,
|
||||
var(--gradient-bg-1) 0%,
|
||||
transparent 25%),
|
||||
radial-gradient(circle at 85% 30%,
|
||||
var(--gradient-bg-2) 0%,
|
||||
transparent 25%);
|
||||
transparent 25%
|
||||
),
|
||||
radial-gradient(circle at 85% 30%, var(--gradient-bg-2) 0%, transparent 25%);
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
transition: background 0.3s ease;
|
||||
@@ -276,9 +276,11 @@ select:focus {
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg,
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
var(--accent-primary),
|
||||
var(--accent-hover));
|
||||
var(--accent-hover)
|
||||
);
|
||||
color: white;
|
||||
box-shadow: 0 4px 12px var(--accent-glow);
|
||||
}
|
||||
@@ -663,3 +665,51 @@ select:focus {
|
||||
.log-output::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* Version Badge */
|
||||
.version-badge {
|
||||
position: fixed;
|
||||
bottom: 1.5rem;
|
||||
right: 1.5rem;
|
||||
background: rgba(15, 23, 42, 0.8);
|
||||
backdrop-filter: blur(8px);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 20px;
|
||||
padding: 0.4rem 0.8rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
[data-theme="light"] .version-badge {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
border-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.version-badge:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.commit-hash {
|
||||
font-family: "JetBrains Mono", monospace;
|
||||
color: #a78bfa; /* Slightly purple to match example */
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-theme="light"] .commit-hash {
|
||||
color: #7c3aed;
|
||||
}
|
||||
|
||||
.commit-sep {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.commit-date {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
62
scripts/setup-server.sh
Normal file
62
scripts/setup-server.sh
Normal file
@@ -0,0 +1,62 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
|
||||
APP_NAME="Advanced-Smtp-Tester"
|
||||
APP_DIR="/var/www/$APP_NAME"
|
||||
|
||||
echo "🚀 Starting Server Setup for $APP_NAME..."
|
||||
|
||||
# 1. Install Dependencies
|
||||
echo "📦 Installing system dependencies..."
|
||||
apt-get update
|
||||
# Note: nodejs and npm should be present in the TurnKey Node.js template
|
||||
apt-get install -y git nginx curl build-essential
|
||||
|
||||
# Install PM2 globally if not exists
|
||||
if ! command -v pm2 &> /dev/null; then
|
||||
echo "📦 Installing PM2..."
|
||||
npm install -g pm2
|
||||
fi
|
||||
|
||||
# 1.1 Install Cloudflared (Optional but recommended)
|
||||
echo "☁️ Installing Cloudflared..."
|
||||
mkdir -p --mode=0755 /usr/share/keyrings
|
||||
curl -fsSL https://pkg.cloudflare.com/cloudflare-public-v2.gpg | tee /usr/share/keyrings/cloudflare-public-v2.gpg >/dev/null
|
||||
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-public-v2.gpg] https://pkg.cloudflare.com/cloudflared any main' | tee /etc/apt/sources.list.d/cloudflared.list
|
||||
apt-get update && apt-get install -y cloudflared
|
||||
|
||||
# 1.2 Install App Dependencies
|
||||
echo "📦 Installing Application Dependencies..."
|
||||
cd "$APP_DIR"
|
||||
npm install
|
||||
|
||||
# 2. Setup Nginx
|
||||
echo "⚙️ Configuring Nginx..."
|
||||
cp "$APP_DIR/config/nginx.conf.template" "/etc/nginx/sites-available/$APP_NAME"
|
||||
# Remove default site if exists
|
||||
rm -f /etc/nginx/sites-enabled/default
|
||||
rm -f /etc/nginx/sites-enabled/nodejs # Common in TurnKey
|
||||
# Enable site
|
||||
ln -sf "/etc/nginx/sites-available/$APP_NAME" "/etc/nginx/sites-enabled/"
|
||||
# Test and Reload
|
||||
nginx -t && systemctl reload nginx
|
||||
|
||||
# 3. Setup PM2
|
||||
echo "⚙️ Configuring PM2..."
|
||||
cd "$APP_DIR"
|
||||
pm2 start ecosystem.config.js
|
||||
pm2 save
|
||||
pm2 startup systemd -u root --hp /root
|
||||
|
||||
# 4. Setup Cron Job for Auto-Sync (Every 5 minutes)
|
||||
echo "⏰ Setting up Auto-Sync Cron Job..."
|
||||
SCRIPT_PATH="$APP_DIR/scripts/sync-and-restart.sh"
|
||||
chmod +x "$SCRIPT_PATH"
|
||||
|
||||
# Add to crontab if not already there
|
||||
(crontab -l 2>/dev/null; echo "*/5 * * * * $SCRIPT_PATH") | awk '!x[$0]++' | crontab -
|
||||
|
||||
echo "✅ Setup Complete! Application is running and auto-sync is enabled."
|
||||
echo "🌐 Access your app at http://<YOUR_SERVER_IP>"
|
||||
52
scripts/sync-and-restart.sh
Normal file
52
scripts/sync-and-restart.sh
Normal file
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Configuration
|
||||
APP_DIR="/var/www/Advanced-Smtp-Tester"
|
||||
LOG_FILE="/var/log/smtp-tester-sync.log"
|
||||
|
||||
# Add /usr/local/bin to PATH to ensure PM2 is found
|
||||
export PATH=$PATH:/usr/local/bin
|
||||
|
||||
# Navigate to app directory
|
||||
cd "$APP_DIR" || exit 1
|
||||
|
||||
# Log function
|
||||
log() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
log "Checking for updates..."
|
||||
|
||||
# Fetch latest changes
|
||||
git fetch origin
|
||||
|
||||
# Check if we are behind
|
||||
LOCAL=$(git rev-parse HEAD)
|
||||
REMOTE=$(git rev-parse @{u}) # This gets the upstream commit for the current branch
|
||||
|
||||
if [ "$LOCAL" != "$REMOTE" ]; then
|
||||
log "Changes detected. Updating..."
|
||||
|
||||
# Force reset to match origin (avoids merge conflicts)
|
||||
git reset --hard origin/main >> "$LOG_FILE" 2>&1
|
||||
|
||||
# Check if package.json changed (compare old local HEAD with new remote HEAD)
|
||||
# Note: git diff --name-only $LOCAL $REMOTE would compare the old local HEAD with the new remote HEAD
|
||||
# After git reset --hard, HEAD is already at REMOTE.
|
||||
# To check if package.json changed *between the old state and the new state*,
|
||||
# we need to compare the old LOCAL with the new REMOTE.
|
||||
if git diff --name-only "$LOCAL" "$REMOTE" | grep "package.json"; then
|
||||
log "package.json changed. Installing dependencies..."
|
||||
npm install >> "$LOG_FILE" 2>&1
|
||||
fi
|
||||
|
||||
log "Restarting application..."
|
||||
pm2 restart Advanced-Smtp-Tester >> "$LOG_FILE" 2>&1
|
||||
|
||||
log "Update complete."
|
||||
else
|
||||
# Uncomment next line for verbose logging of no-changes
|
||||
# log "No changes detected."
|
||||
# echo "No changes."
|
||||
log "No changes found."
|
||||
fi
|
||||
20
server.js
20
server.js
@@ -3,10 +3,25 @@ const nodemailer = require("nodemailer");
|
||||
const bodyParser = require("body-parser");
|
||||
const cors = require("cors");
|
||||
const path = require("path");
|
||||
const { execSync } = require("child_process");
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 3000;
|
||||
|
||||
// Get Git Commit Info
|
||||
let gitInfo = {
|
||||
hash: 'Unknown',
|
||||
date: 'Unknown'
|
||||
};
|
||||
|
||||
try {
|
||||
const hash = execSync('git log -1 --format="%h"').toString().trim();
|
||||
const date = execSync('git log -1 --format="%cd"').toString().trim();
|
||||
gitInfo = { hash, date };
|
||||
} catch (e) {
|
||||
console.warn("Could not retrieve git info:", e.message);
|
||||
}
|
||||
|
||||
app.use(cors());
|
||||
app.use(bodyParser.json());
|
||||
|
||||
@@ -18,6 +33,11 @@ app.get('/', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, 'index.html'));
|
||||
});
|
||||
|
||||
// API Endpoint for Version Info
|
||||
app.get('/api/version', (req, res) => {
|
||||
res.json(gitInfo);
|
||||
});
|
||||
|
||||
app.post('/api/test-smtp', async (req, res) => {
|
||||
const { host, port, secure, user, pass, from, to } = req.body;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user