mirror of
https://github.com/DeNNiiInc/Advanced-Smtp-Tester.git
synced 2026-04-19 18:25:59 +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
|
.DS_Store
|
||||||
*.log
|
*.log
|
||||||
.env
|
.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
|
Test SMTP configurations, troubleshoot connection issues, and validate email delivery with an elegant, intuitive 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
|
|
||||||
|
|
||||||
### 🖥️ Desktop Application
|
<div align="center">
|
||||||
- **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
|
|
||||||
|
|
||||||
### 📧 SMTP Testing
|
[](https://advanced-smtp-tester.beyondcloud.technology/)
|
||||||
- **Multiple Encryption** - STARTTLS, SSL/TLS, Unencrypted
|
[](https://github.com/DeNNiiInc/Advanced-Smtp-Tester)
|
||||||
- **Auto-Discovery** - Test multiple port/encryption combinations
|
[](LICENSE)
|
||||||
- **Beautiful Emails** - Professional HTML test emails
|
|
||||||
- **Detailed Results** - Full response logs and error messages
|
|
||||||
|
|
||||||
## 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
|
## 🌐 Live Demo
|
||||||
3. Run `Advanced-SMTP-Tester.exe`
|
|
||||||
|
**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
|
```bash
|
||||||
|
# Clone the repository
|
||||||
|
git clone https://github.com/DeNNiiInc/Advanced-Smtp-Tester.git
|
||||||
|
cd Advanced-Smtp-Tester
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
|
# Start the server
|
||||||
npm start
|
npm start
|
||||||
```
|
|
||||||
Open `http://localhost:3000` in your browser.
|
|
||||||
|
|
||||||
### Electron Development
|
# Access at http://localhost:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 3: Desktop App (Electron)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install
|
# Development mode
|
||||||
npm run electron
|
npm run electron
|
||||||
```
|
|
||||||
|
|
||||||
## Building from Source
|
# Build Windows installer
|
||||||
|
|
||||||
### Web Version
|
|
||||||
```bash
|
|
||||||
npm install
|
|
||||||
npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
### Desktop App
|
|
||||||
```bash
|
|
||||||
npm install
|
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
Or use electron-packager:
|
### Option 4: Automated Proxmox Deployment
|
||||||
```bash
|
|
||||||
npx electron-packager . "Advanced-SMTP-Tester" --platform=win32 --arch=x64 --out=dist --overwrite
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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
|
### Quick Start
|
||||||
1. Select a preset (e.g., "Microsoft Office 365")
|
1. Visit [https://advanced-smtp-tester.beyondcloud.technology/](https://advanced-smtp-tester.beyondcloud.technology/)
|
||||||
2. Enter your credentials
|
2. Select a preset (e.g., "Microsoft Office 365")
|
||||||
3. Enter recipient email
|
3. Enter your credentials
|
||||||
4. Click "Test Configuration & Send Email"
|
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
|
### 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
|
| Provider | Host | Port | Encryption |
|
||||||
Click "Auto Discovery Test" to automatically test multiple port/encryption combinations.
|
|----------|------|------|------------|
|
||||||
|
| **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
|
## 🛠️ Technology Stack
|
||||||
```
|
|
||||||
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
|
|
||||||
|
|
||||||
- **Backend**: Node.js, Express, Nodemailer
|
- **Backend**: Node.js, Express, Nodemailer
|
||||||
- **Frontend**: Vanilla JavaScript, IndexedDB
|
- **Frontend**: Vanilla JavaScript, IndexedDB
|
||||||
- **Desktop**: Electron
|
- **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)
|
## 📄 License
|
||||||
- [YouTube Channel](https://www.youtube.com/@beyondcloudtechnology)
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
};
|
||||||
109
index.html
109
index.html
@@ -1,10 +1,12 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
<head>
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<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>
|
<title>Advanced SMTP Tester</title>
|
||||||
<link rel="icon" type="image/png" href="public/Logo.png" />
|
<link rel="icon" type="image/png" href="public/Logo.png" />
|
||||||
<link rel="stylesheet" href="public/styles.css" />
|
<link rel="stylesheet" href="public/styles.css" />
|
||||||
@@ -14,10 +16,11 @@
|
|||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap"
|
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>
|
/>
|
||||||
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<!-- Theme Toggle -->
|
<!-- Theme Toggle -->
|
||||||
<button class="theme-toggle" id="themeToggle" aria-label="Toggle theme">
|
<button class="theme-toggle" id="themeToggle" aria-label="Toggle theme">
|
||||||
🌙
|
🌙
|
||||||
@@ -36,11 +39,16 @@
|
|||||||
<p class="subtitle">
|
<p class="subtitle">
|
||||||
Advanced SMTP Configuration & Delivery Testing Utility
|
Advanced SMTP Configuration & Delivery Testing Utility
|
||||||
</p>
|
</p>
|
||||||
<a href="https://www.youtube.com/@beyondcloudtechnology" target="_blank" rel="noopener noreferrer"
|
<a
|
||||||
class="youtube-link">
|
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">
|
<svg class="youtube-icon" viewBox="0 0 24 24" fill="currentColor">
|
||||||
<path
|
<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>
|
</svg>
|
||||||
Watch on YouTube @beyondcloudtechnology
|
Watch on YouTube @beyondcloudtechnology
|
||||||
</a>
|
</a>
|
||||||
@@ -66,6 +74,7 @@
|
|||||||
<option value="sendgrid">SendGrid</option>
|
<option value="sendgrid">SendGrid</option>
|
||||||
<option value="mailgun">Mailgun</option>
|
<option value="mailgun">Mailgun</option>
|
||||||
<option value="amazonses">Amazon SES</option>
|
<option value="amazonses">Amazon SES</option>
|
||||||
|
<option value="mailassure">Mail Assure</option>
|
||||||
<option value="custom">💾 Last Used Configuration</option>
|
<option value="custom">💾 Last Used Configuration</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -74,11 +83,23 @@
|
|||||||
<!-- Server Details -->
|
<!-- Server Details -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="host">SMTP Host</label>
|
<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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="port">Port</label>
|
<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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="secure">Encryption</label>
|
<label for="secure">Encryption</label>
|
||||||
@@ -92,13 +113,29 @@
|
|||||||
<!-- Auth Details -->
|
<!-- Auth Details -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="user">Username / Email</label>
|
<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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="pass">Password</label>
|
<label for="pass">Password</label>
|
||||||
<div class="password-input-wrapper">
|
<div class="password-input-wrapper">
|
||||||
<input type="password" id="pass" name="pass" placeholder="••••••••" required />
|
<input
|
||||||
<button type="button" class="toggle-password" onclick="togglePassword()">
|
type="password"
|
||||||
|
id="pass"
|
||||||
|
name="pass"
|
||||||
|
placeholder="••••••••"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="toggle-password"
|
||||||
|
onclick="togglePassword()"
|
||||||
|
>
|
||||||
👁️
|
👁️
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -107,11 +144,22 @@
|
|||||||
<!-- Email Details -->
|
<!-- Email Details -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="from">From Address (Optional)</label>
|
<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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="to">To Address</label>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -147,10 +195,14 @@
|
|||||||
<div class="history-panel" id="historyPanel">
|
<div class="history-panel" id="historyPanel">
|
||||||
<div class="history-header">
|
<div class="history-header">
|
||||||
<h3>📋 Test History</h3>
|
<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>
|
||||||
<div id="historyList">
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -159,19 +211,30 @@
|
|||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<p>© 2025 Beyond Cloud Technology. All rights reserved.</p>
|
<p>© 2025 Beyond Cloud Technology. All rights reserved.</p>
|
||||||
<a href="https://github.com/DeNNiiInc/Advanced-Smtp-Tester" target="_blank" rel="noopener noreferrer"
|
<a
|
||||||
class="github-link">
|
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">
|
<svg class="github-icon" viewBox="0 0 24 24" fill="currentColor">
|
||||||
<path
|
<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>
|
</svg>
|
||||||
View on GitHub
|
View on GitHub
|
||||||
</a>
|
</a>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</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/db.js"></script>
|
||||||
<script src="public/script.js"></script>
|
<script src="public/script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -34,6 +34,12 @@ const PRESETS = {
|
|||||||
port: '587',
|
port: '587',
|
||||||
secure: 'false',
|
secure: 'false',
|
||||||
name: 'Amazon SES'
|
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;
|
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
|
// 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
|
// INITIALIZATION
|
||||||
// ===================================
|
// ===================================
|
||||||
@@ -482,6 +545,9 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||||||
// Load history
|
// Load history
|
||||||
await loadHistory();
|
await loadHistory();
|
||||||
|
|
||||||
|
// Load Version Info
|
||||||
|
await loadVersionInfo();
|
||||||
|
|
||||||
// Load last used configuration
|
// Load last used configuration
|
||||||
const settings = await window.smtpDB.getSettings();
|
const settings = await window.smtpDB.getSettings();
|
||||||
if (settings) {
|
if (settings) {
|
||||||
|
|||||||
@@ -77,12 +77,12 @@ body {
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: radial-gradient(circle at 15% 50%,
|
background: radial-gradient(
|
||||||
|
circle at 15% 50%,
|
||||||
var(--gradient-bg-1) 0%,
|
var(--gradient-bg-1) 0%,
|
||||||
transparent 25%),
|
transparent 25%
|
||||||
radial-gradient(circle at 85% 30%,
|
),
|
||||||
var(--gradient-bg-2) 0%,
|
radial-gradient(circle at 85% 30%, var(--gradient-bg-2) 0%, transparent 25%);
|
||||||
transparent 25%);
|
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
transition: background 0.3s ease;
|
transition: background 0.3s ease;
|
||||||
@@ -276,9 +276,11 @@ select:focus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background: linear-gradient(135deg,
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
var(--accent-primary),
|
var(--accent-primary),
|
||||||
var(--accent-hover));
|
var(--accent-hover)
|
||||||
|
);
|
||||||
color: white;
|
color: white;
|
||||||
box-shadow: 0 4px 12px var(--accent-glow);
|
box-shadow: 0 4px 12px var(--accent-glow);
|
||||||
}
|
}
|
||||||
@@ -449,7 +451,7 @@ select:focus {
|
|||||||
.github-icon {
|
.github-icon {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
}/* Theme Toggle Button */
|
} /* Theme Toggle Button */
|
||||||
.theme-toggle {
|
.theme-toggle {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 1.5rem;
|
top: 1.5rem;
|
||||||
@@ -663,3 +665,51 @@ select:focus {
|
|||||||
.log-output::-webkit-scrollbar-thumb:hover {
|
.log-output::-webkit-scrollbar-thumb:hover {
|
||||||
background: var(--text-secondary);
|
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 bodyParser = require("body-parser");
|
||||||
const cors = require("cors");
|
const cors = require("cors");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
const { execSync } = require("child_process");
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const port = process.env.PORT || 3000;
|
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(cors());
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
|
|
||||||
@@ -18,6 +33,11 @@ app.get('/', (req, res) => {
|
|||||||
res.sendFile(path.join(__dirname, 'index.html'));
|
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) => {
|
app.post('/api/test-smtp', async (req, res) => {
|
||||||
const { host, port, secure, user, pass, from, to } = req.body;
|
const { host, port, secure, user, pass, from, to } = req.body;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user