Пожалуйста, обратите внимание, что пользователь заблокирован
Простой SMTP Спаммер с веб панелью и уникализацией текста через API ChatGPT, ну и само собой с использованием прокси
Ну а также для удобства отслеживания: отстук статуса процессов в телегу
Данный продукт был написан давненько и никем не реализован, поэтому оставляю тут)
Используется Node.js (да здравствуй хардкод)
.env:
Код:
USERS=
TELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=
main.js:
JavaScript:
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const bodyParser = require('body-parser');
const nodemailer = require('nodemailer');
const imapClient = require('imap-simple');
const fs = require('fs');
const path = require('path');
const multer = require('multer');
const dotenv = require('dotenv');
const session = require('express-session');
const { Configuration, OpenAIApi } = require('openai');
const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
const app = express();
dotenv.config();
const PORT = 3000;
const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: "*"
}
});
let subjects = [];
let proxies = [];
async function uniquifyText(text) {
const API_KEY = '';
const API_URL = 'https://api.openai.com/v1/chat/completions';
const payload = {
model: 'gpt-3.5-turbo',
messages: [
{
role: 'system',
content: 'Вы помощник, который делает текст уникальным.'
},
{
role: 'user',
content: `Перепиши следующий текст полностью своими словами, сохраняя общий смысл, но делая его уникальным и подходящим для новой аудитории. Избегай точного копирования структуры предложений и используемых формулировок. Постарайся сделать текст лаконичным, но при этом информативным. Убедись, что итоговый текст будет легким для восприятия и грамматически правильным. Используй только английский язык:\n${text}`
}
],
max_tokens: 500,
temperature: 0.7,
};
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`,
};
try {
console.log('Sending request to OpenAI API...');
const response = await axios.post(API_URL, payload, { headers });
console.log('OpenAI API response:', JSON.stringify(response.data, null, 2));
if (
response.data &&
response.data.choices &&
response.data.choices[0] &&
response.data.choices[0].message &&
response.data.choices[0].message.content
) {
return response.data.choices[0].message.content.trim();
} else {
throw new Error('Response does not contain valid content.');
}
} catch (error) {
const errorMessage = error.response ? JSON.stringify(error.response.data, null, 2) : error.message;
console.error('Error with OpenAI API:', errorMessage);
throw new Error(`Failed to uniquify text: ${errorMessage}`);
}
}
const upload = multer({ dest: 'uploads/' });
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(session({
secret: 'secret-key',
resave: false,
saveUninitialized: true
}));
function isAuthenticated(req, res, next) {
if (req.session && req.session.loggedIn) {
return next();
} else {
res.redirect('/login');
}
}
const users = process.env.USERS ? process.env.USERS.split(',').map(user => {
const [username, password] = user.split(':');
return { username, password };
}) : [];
app.get('/login', (req, res) => {
res.send(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
<style>
body {
background-color: #1e1e1e;
color: #c0c0c0;
font-family: "Courier New", Courier, monospace;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
form {
background-color: #2a2a2a;
border: 1px solid #ff4040;
border-radius: 8px;
padding: 20px;
text-align: center;
width: 300px;
}
input, button {
width: calc(100% - 20px);
margin: 10px 0;
padding: 10px;
background-color: #3a3a3a;
border: 1px solid #ff4040;
color: #c0c0c0;
border-radius: 5px;
}
button {
cursor: pointer;
background-color: #5d0000;
}
button:hover {
background-color: #ff4040;
color: #000;
}
</style>
</head>
<body>
<form action="/login" method="POST">
<h3>Login</h3>
<input type="text" name="username" placeholder="Username" required />
<input type="password" name="password" placeholder="Password" required />
<button type="submit">Login</button>
</form>
</body>
</html>`);
});
app.post('/login', (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username && u.password === password);
if (user) {
req.session.loggedIn = true;
res.redirect('/');
} else {
res.send('<h3>Invalid credentials. <a href="/login">Try again</a></h3>');
}
});
app.get('/logout', (req, res) => {
req.session.destroy(() => {
res.redirect('/login');
});
});
app.use((req, res, next) => {
if (req.session && req.session.loggedIn) {
express.static('public')(req, res, next);
} else {
next();
}
});
app.use(isAuthenticated);
let smtpCredentials = [];
let recipients = [];
const sendTelegramMessage = async (message) => {
const botToken = process.env.TELEGRAM_BOT_TOKEN;
const chatId = process.env.TELEGRAM_CHAT_ID;
if (!botToken || !chatId) {
console.error('Telegram bot token or chat ID is not defined');
return;
}
const apiUrl = `https://api.telegram.org/bot${botToken}/sendMessage`;
try {
await axios.post(apiUrl, {
chat_id: chatId,
text: message,
});
} catch (error) {
console.error('Error sending message to Telegram:', error.message);
}
};
app.post('/upload-subjects', upload.single('file'), (req, res) => {
const filePath = req.file.path;
console.log('Uploading subjects from file:', filePath);
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
console.error('Error reading subjects file:', err);
return res.status(500).send({ message: 'Error reading file' });
}
// Разделяем по переносу строк
subjects = data.split('\n').map(line => line.trim()).filter(line => line);
console.log('Parsed subjects:', subjects);
fs.unlinkSync(filePath);
res.send({ message: 'Subjects uploaded successfully' });
});
});
app.post('/upload-smtp', upload.single('file'), (req, res) => {
const filePath = req.file.path;
console.log('Uploading SMTP credentials from file:', filePath);
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
console.error('Error reading SMTP file:', err);
return res.status(500).send({ message: 'Error reading file' });
}
smtpCredentials = data
.split('\n')
.map(line => {
const [user, pass] = line.trim().split(':');
return { user, pass };
})
.filter(cred => cred.user && cred.pass);
console.log('Parsed SMTP credentials:', smtpCredentials);
fs.unlinkSync(filePath);
res.send({ message: 'SMTP credentials uploaded' });
});
});
app.get('/view-inbox', async (req, res) => {
if (smtpCredentials.length === 0) {
return res.status(400).send({ message: 'No SMTP credentials available' });
}
const results = [];
for (const credential of smtpCredentials) {
try {
const config = {
imap: {
user: credential.user,
password: credential.pass,
host: 'mail.inbox.lv',
port: 993,
tls: true
}
};
const connection = await imapClient.connect(config);
await connection.openBox('INBOX');
const searchCriteria = ['ALL'];
const fetchOptions = {
bodies: ['HEADER', 'TEXT'],
markSeen: false
};
const messages = await connection.search(searchCriteria, fetchOptions);
messages.forEach(item => {
const header = item.parts.find(part => part.which === 'HEADER');
const textPart = item.parts.find(part => part.which === 'TEXT');
const subject = header?.body?.subject ? header.body.subject[0] : 'No Subject';
const from = header?.body?.from ? header.body.from[0] : 'Unknown Sender';
results.push({
user: credential.user,
subject: subject,
from: from,
content: textPart ? textPart.body : 'No Content'
});
});
await connection.end();
} catch (error) {
console.error(`Error fetching emails for ${credential.user}:`, error);
}
}
res.send(results);
});
app.post('/upload-recipients', upload.single('file'), (req, res) => {
const filePath = req.file.path;
console.log('Uploading recipients from file:', filePath);
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
console.error('Error reading recipients file:', err);
return res.status(500).send({ message: 'Error reading file' });
}
recipients = data.split('\n').map(email => email.trim()).filter(email => email);
console.log('Parsed recipients:', recipients);
fs.unlinkSync(filePath);
res.send({ message: 'Recipients uploaded' });
});
});
let activeProcesses = [];
function findProcessById(processId) {
return activeProcesses.find(p => p.id === processId);
}
function removeProcessById(processId) {
activeProcesses = activeProcesses.filter(p => p.id !== processId);
}
app.post('/processes/:id/stop', (req, res) => {
const { id } = req.params;
const process = findProcessById(id);
if (!process) {
return res.status(404).json({ message: 'Process not found' });
}
sendTelegramMessage(`Process stopped:\nID: ${id}`);
process.cancel = true;
res.json({ message: `Process ${id} stopping...` });
});
app.get('/processes', (req, res) => {
res.json(activeProcesses);
});
app.post('/upload-proxies', upload.single('file'), (req, res) => {
const filePath = req.file.path;
console.log('Uploading proxies from file:', filePath);
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
console.error('Error reading proxies file:', err);
return res.status(500).send({ message: 'Error reading file' });
}
proxies = data
.split('\n')
.map(line => line.trim())
.filter(proxy => proxy);
console.log('Parsed proxies:', proxies);
fs.unlinkSync(filePath);
res.send({ message: 'Proxies uploaded successfully' });
});
});
function assignProxiesToAccounts(accounts) {
const proxyMap = new Map();
let proxyIndex = 0;
accounts.forEach(account => {
if (!proxies.length) {
console.error('No proxies available');
return;
}
const proxy = proxies[proxyIndex];
proxyMap.set(account, proxy);
proxyIndex = (proxyIndex + 1) % proxies.length;
});
return proxyMap;
}
function isValidEmail(email) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email);
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function sendEmailsProcess(processObj) {
const {
id,
message,
limitNum,
intervalNum,
unique,
credentials,
recs,
subs
} = processObj;
const maxCount = Math.min(recs.length, subs.length);
processObj.totalSent = 0;
let currentIndex = 0;
processObj.usedRecipients = new Set();
const proxyMap = assignProxiesToAccounts(credentials);
for (let round = 0; round < limitNum; round++) {
if (processObj.cancel) {
processObj.status = 'canceled';
console.log(`Process ${id} was canceled.`);
sendTelegramMessage(`Process stopped:\nID: ${id}`);
removeProcessById(id);
io.emit('processUpdate', activeProcesses);
return;
}
for (const credential of credentials) {
if (currentIndex >= maxCount) break;
const currentRecipient = recs[currentIndex];
const currentSubject = subs[currentIndex];
if (processObj.usedRecipients.has(currentRecipient)) {
currentIndex++;
continue;
}
processObj.usedRecipients.add(currentRecipient);
if (!isValidEmail(currentRecipient)) {
console.warn(`Invalid email address: ${currentRecipient}. Skipping...`);
currentIndex++;
continue;
}
let finalMessage = message;
if (unique === 'true') {
try {
finalMessage = await uniquifyText(message);
} catch (error) {
console.error(`Error uniquifying text for ${currentRecipient}:`, error.message);
currentIndex++;
continue;
}
}
const proxy = proxyMap.get(credential);
const transportOptions = {
host: 'mail.inbox.lv',
port: 465,
secure: true,
auth: {
user: credential.user,
pass: credential.pass
}
};
if (proxy) {
const agent = new HttpsProxyAgent(proxy);
transportOptions.agent = agent;
}
const transporter = nodemailer.createTransport(transportOptions);
const mailOptions = {
from: `<${credential.user}>`,
to: currentRecipient,
subject: currentSubject,
text: finalMessage,
replyTo: processObj.replyTo || credential.user,
};
try {
await transporter.sendMail(mailOptions);
console.log(`Email sent to ${currentRecipient} using ${credential.user} | Subject: ${currentSubject}`);
processObj.totalSent++;
} catch (err) {
if (err.message.includes("all recipients were rejected")) {
console.warn(`Skipped address ${currentRecipient}: ${err.message}`);
} else {
console.error(`Error sending email to ${currentRecipient}:`, err.message);
}
}
currentIndex++;
await delay(500);
processObj.remainingTime = (limitNum - (round + 1)) * intervalNum;
io.emit('processUpdate', activeProcesses);
}
if (round < limitNum - 1) {
await delay(intervalNum * 1000);
}
}
sendTelegramMessage(`Process completed:\nID: ${id}\nTotal Sent: ${processObj.totalSent}`);
processObj.status = 'completed';
io.emit('processUpdate', activeProcesses);
removeProcessById(id);
}
app.post('/send-emails', upload.none(), async (req, res) => {
const { message, limit, interval, unique, replyTo } = req.body;
if (!message || !limit || !interval) {
return res.status(400).send({ message: 'Missing required parameters (message, limit, interval)' });
}
if (smtpCredentials.length === 0 || recipients.length === 0 || subjects.length === 0) {
return res.status(400).send({ message: 'No SMTP credentials, or recipients, or subjects available' });
}
try {
const limitNum = parseInt(limit, 10);
const intervalNum = parseInt(interval, 10);
const processId = Date.now().toString();
const newProcess = {
id: processId,
message,
limitNum,
intervalNum,
unique,
replyTo,
credentials: smtpCredentials,
recs: recipients,
subs: subjects,
cancel: false,
status: 'running',
totalSent: 0,
remainingTime: 0,
totalRecipients: recipients.length,
settings: {
limitNum,
intervalNum,
unique,
replyTo,
},
};
activeProcesses.push(newProcess);
sendTelegramMessage(`Process started:\nID: ${processId}`);
sendEmailsProcess(newProcess).catch(err => {
console.error('Error during email sending process (inside promise):', err);
newProcess.status = 'error';
io.emit('processUpdate', activeProcesses);
removeProcessById(processId);
});
res.send({ message: `Process started. ID = ${processId}` });
} catch (err) {
console.error('Error during email sending process:', err);
res.status(500).send({ message: 'Error sending emails' });
}
});
app.get('/email-content/:user/:subject', async (req, res) => {
const { user, subject } = req.params;
console.log('Fetching email content for user:', user, 'subject:', subject);
const credential = smtpCredentials.find(cred => cred.user === user);
if (!credential) {
console.error('User not found:', user);
return res.status(400).send({ message: 'Invalid user' });
}
try {
const config = {
imap: {
user: credential.user,
password: credential.pass,
host: 'mail.inbox.lv',
port: 993,
tls: true
}
};
const connection = await imapClient.connect(config);
await connection.openBox('INBOX');
const searchCriteria = ['ALL'];
const fetchOptions = {
bodies: ['HEADER', 'TEXT'],
markSeen: false
};
const messages = await connection.search(searchCriteria, fetchOptions);
console.log('Found messages:', messages.length);
const messageData = messages.find(msg => {
const header = msg.parts.find(part => part.which === 'HEADER');
if (!header?.body?.subject?.[0]) return false;
return header.body.subject[0] === subject;
});
if (!messageData) {
console.error('Email not found for subject:', subject);
return res.status(404).send({ message: 'Email not found' });
}
const textPart = messageData.parts.find(part => part.which === 'TEXT');
res.send({ content: textPart.body });
} catch (error) {
console.error('Error fetching email content:', error);
res.status(500).send({ message: 'Error fetching email content' });
}
});
app.get('/get-logpass/:user', (req, res) => {
const { user } = req.params;
const credential = smtpCredentials.find(cred => cred.user === user);
if (!credential) {
return res.status(400).send({ message: 'User not found' });
}
res.send({ logpass: `${credential.user}:${credential.pass}` });
});
app.get('/', (req, res) => {
console.log('Serving HTML file to client');
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
const publicPath = path.join(__dirname, 'public');
if (!fs.existsSync(publicPath)) fs.mkdirSync(publicPath);
fs.writeFileSync(
path.join(publicPath, 'index.html'),
`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Email App</title>
<style>
body {
background-color: #1e1e1e;
color: #c0c0c0;
font-family: "Courier New", Courier, monospace;
margin: 0;
padding: 0;
}
h1, h3 {
color: #ff4040;
}
form {
background-color: #2a2a2a;
border: 1px solid #ff4040;
border-radius: 8px;
padding: 20px;
margin: 20px auto;
max-width: 500px;
}
input, textarea, button {
width: calc(100% - 20px);
margin: 10px 0;
padding: 10px;
background-color: #3a3a3a;
border: 1px solid #ff4040;
color: #c0c0c0;
border-radius: 5px;
}
button {
cursor: pointer;
width:100%;
background-color: #5d0000;
}
button:hover {
background-color: #ff4040;
color: #000;
}
#inboxSection {
margin: 20px auto;
max-width: 500px;
background-color: #2a2a2a;
border: 1px solid #ff4040;
border-radius: 8px;
padding: 20px;
}
ul {
list-style-type: none;
padding: 0;
}
li {
background-color: #3a3a3a;
margin: 10px 0;
padding: 10px;
border: 1px solid #ff4040;
border-radius: 5px;
}
li:hover {
background-color: #ff4040;
color: #000;
}
.filter-input {
margin-bottom: 10px;
}
/* Новый блок для управления процессами */
#processesPanel {
margin: 20px auto;
max-width: 900px;
background-color: #2a2a2a;
border: 1px solid #ff4040;
border-radius: 8px;
padding: 20px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
table thead {
background-color: #3a3a3a;
}
table th, table td {
border: 1px solid #ff4040;
padding: 8px;
text-align: center;
}
table th {
color: #ff4040;
}
table td button {
width: auto;
background-color: #3a3a3a;
}
table td button:hover {
background-color: #ff4040;
color: #000;
}
</style>
</head>
<body>
<form id="proxiesForm" style="margin-top: 20px;" enctype="multipart/form-data">
<h3>Upload Proxies</h3>
<input type="file" name="file" required />
<button type="submit">Upload</button>
</form>
<form id="smtpForm" style="margin-top: 20px;" enctype="multipart/form-data">
<h3>Upload SMTP Credentials</h3>
<input type="file" name="file" required />
<button type="submit">Upload</button>
</form>
<form id="recipientsForm" style="margin-top: 20px;" enctype="multipart/form-data">
<h3>Upload Recipients</h3>
<input type="file" name="file" required />
<button type="submit">Upload</button>
</form>
<form id="subjectsForm" style="margin-top: 20px;" enctype="multipart/form-data">
<h3>Upload Subjects</h3>
<input type="file" name="file" required />
<button type="submit">Upload</button>
</form>
<form id="emailForm" style="margin-top: 20px;">
<h3>Send Emails</h3>
<textarea name="message" placeholder="Message" required></textarea>
<input type="number" name="limit" placeholder="Limit" required />
<input type="number" name="interval" placeholder="Interval (seconds)" required />
<input type="email" name="replyTo" placeholder="Reply-To Email (optional)" />
<label style="display:flex;align-items:center;">
<input style="width:50px;" type="checkbox" name="unique" value="true" />
<p>Unique Text</p>
</label>
<button type="submit">Send Emails</button>
</form>
<!-- Панель процессов -->
<div id="processesPanel">
<h3>Processes Panel</h3>
<table>
<thead>
<tr>
<th>Process ID</th>
<th>Recievers</th>
<th>Sent</th>
<th>Remaining time (sec)</th>
<th>Parametres</th>
<th>Status</th>
<th>Stop</th>
</tr>
</thead>
<tbody id="processesTableBody"></tbody>
</table>
</div>
<form id="viewInboxForm" style="margin-top: 20px;">
<h3>View Inbox</h3>
<button type="button" id="viewInboxButton">View Inbox</button>
</form>
<div id="inboxSection" style="margin-top: 20px;">
<h3>Inbox Messages</h3>
<input type="text" id="filterInput" class="filter-input" placeholder="Enter keyword to filter by subject" />
<button type="button" id="filterButton">Filter</button>
<ul id="inboxMessages" style="list-style-type: none; padding: 0;"></ul>
</div>
<!-- Подключаем socket.io -->
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
socket.on('processUpdate', (processes) => {
renderProcesses(processes);
});
function renderProcesses(processes) {
const tbody = document.getElementById('processesTableBody');
tbody.innerHTML = '';
processes.forEach(proc => {
const tr = document.createElement('tr');
const tdId = document.createElement('td');
tdId.textContent = proc.id;
tr.appendChild(tdId);
const tdTotalRecipients = document.createElement('td');
tdTotalRecipients.textContent = proc.totalRecipients || 0; // Используем totalRecipients из объекта процесса
tr.appendChild(tdTotalRecipients);
const tdSent = document.createElement('td');
tdSent.textContent = proc.totalSent;
tr.appendChild(tdSent);
const tdTime = document.createElement('td');
tdTime.textContent = proc.remainingTime;
tr.appendChild(tdTime);
const tdSettings = document.createElement('td');
const s = proc.settings || {};
tdSettings.textContent = \`limit=\${s.limitNum}, interval=\${s.intervalNum}, unique=\${s.unique}\`;
tr.appendChild(tdSettings);
const tdStatus = document.createElement('td');
tdStatus.textContent = proc.status;
tr.appendChild(tdStatus);
const tdStop = document.createElement('td');
if (proc.status === 'running') {
const stopBtn = document.createElement('button');
stopBtn.textContent = 'STOP';
stopBtn.onclick = () => stopProcess(proc.id);
tdStop.appendChild(stopBtn);
} else {
tdStop.textContent = '-';
}
tr.appendChild(tdStop);
tbody.appendChild(tr);
});
}
async function stopProcess(processId) {
try {
const response = await fetch('/processes/' + processId + '/stop', {
method: 'POST'
});
const data = await response.json();
alert(data.message);
} catch (err) {
console.error(err);
}
}
async function fetchProcesses() {
try {
const res = await fetch('/processes');
const data = await res.json();
renderProcesses(data);
} catch (err) {
console.error(err);
}
}
setInterval(fetchProcesses, 5000);
async function submitForm(event, endpoint) {
event.preventDefault();
const formData = new FormData(event.target);
try {
const response = await fetch(endpoint, {
method: 'POST',
body: formData
});
const result = await response.json();
alert(result.message);
} catch (error) {
console.error('Error:', error);
alert('An error occurred');
}
}
let allInboxMessages = [];
async function viewInbox() {
var inboxMessagesList = document.getElementById('inboxMessages');
inboxMessagesList.innerHTML = '';
try {
var response = await fetch('/view-inbox');
var inboxMessages = await response.json();
if (inboxMessages.length === 0) {
inboxMessagesList.innerHTML = '<li>No messages found</li>';
return;
}
allInboxMessages = inboxMessages;
inboxMessages.forEach(function (message, index) {
var listItem = document.createElement('li');
listItem.innerHTML =
'<b>Получил письмо</b> ' + message.user +
' <b>от</b> ' + message.from +
', <b>тема:</b> ' + message.subject +
'<br>' +
'<div style="display:flex;gap:10px;"><button onclick="viewEmailContent(' + index + ')">Content</button><button onclick="getLogPass(' + "'" + message.user + "'" + ')">log:pass</button></div>' +
'<button onclick="">RE</button>';
inboxMessagesList.appendChild(listItem);
});
} catch (error) {
console.error('Error fetching inbox messages:', error);
alert('An error occurred while fetching inbox messages.');
}
}
function viewEmailContent(index) {
var message = allInboxMessages[index];
if (message && message.content) {
alert('Content: ' + message.content);
} else {
alert('No content available for this message.');
}
}
async function getLogPass(user) {
try {
var response = await fetch('/get-logpass/' + user);
var result = await response.json();
alert('Log:Pass = ' + result.logpass);
} catch (error) {
console.error('Error fetching log:pass:', error);
alert('An error occurred while fetching log:pass.');
}
}
function filterInbox() {
const filterInput = document.getElementById('filterInput').value.toLowerCase();
const inboxMessagesList = document.getElementById('inboxMessages');
inboxMessagesList.innerHTML = '';
const filteredMessages = allInboxMessages.filter(message =>
message.subject.toLowerCase().includes(filterInput)
);
if (filteredMessages.length === 0) {
inboxMessagesList.innerHTML = '<li>No messages match the filter</li>';
return;
}
filteredMessages.forEach(message => {
const listItem = document.createElement('li');
listItem.textContent = 'Получил письмо ' + message.user + ' от ' + message.from + ', тема: ' + message.subject;
inboxMessagesList.appendChild(listItem);
});
}
document.getElementById('proxiesForm').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
try {
const response = await fetch('/upload-proxies', {
method: 'POST',
body: formData
});
const result = await response.json();
alert(result.message);
} catch (error) {
console.error('Error uploading proxies:', error);
alert('An error occurred while uploading proxies.');
}
});
document.getElementById('smtpForm').addEventListener('submit', (e) => submitForm(e, '/upload-smtp'));
document.getElementById('recipientsForm').addEventListener('submit', (e) => submitForm(e, '/upload-recipients'));
document.getElementById('subjectsForm').addEventListener('submit', (e) => submitForm(e, '/upload-subjects'));
document.getElementById('emailForm').addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
try {
const response = await fetch('/send-emails', {
method: 'POST',
body: formData
});
const result = await response.json();
alert(result.message);
} catch (error) {
console.error('Error:', error);
alert('An error occurred');
}
});
document.getElementById('viewInboxButton').addEventListener('click', viewInbox);
document.getElementById('filterButton').addEventListener('click', filterInbox);
fetchProcesses();
</script>
</body>
</html>
`
);
server.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});