-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py.backup
More file actions
executable file
·258 lines (217 loc) · 8.61 KB
/
app.py.backup
File metadata and controls
executable file
·258 lines (217 loc) · 8.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#!/usr/bin/env python3
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify
import subprocess
import os
import re
from datetime import datetime
app = Flask(__name__)
app.secret_key = 'smtp-panel-secret-key-2024'
POSTFIX_VIRTUAL_DIR = '/etc/postfix/virtual'
DOMAINS_FILE = f'{POSTFIX_VIRTUAL_DIR}/domains'
ALIASES_FILE = f'{POSTFIX_VIRTUAL_DIR}/aliases'
DKIM_DIR = '/etc/opendkim/keys'
def run_command(cmd):
"""Execute shell command and return result"""
try:
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
return result.returncode == 0, result.stdout, result.stderr
except Exception as e:
return False, '', str(e)
def get_domains():
"""Get list of configured domains"""
domains = []
if os.path.exists(DOMAINS_FILE):
with open(DOMAINS_FILE, 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('#'):
domain = line.split()[0]
domains.append(domain)
return domains
def get_aliases():
"""Get list of configured aliases"""
aliases = []
if os.path.exists(ALIASES_FILE):
with open(ALIASES_FILE, 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('#'):
parts = line.split()
if len(parts) >= 2:
aliases.append({'email': parts[0], 'destination': ' '.join(parts[1:])})
return aliases
def add_domain(domain):
"""Add new domain to virtual domains"""
if not re.match(r'^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', domain):
return False, 'Invalid domain format'
domains = get_domains()
if domain in domains:
return False, 'Domain already exists'
# Add domain to file
with open(DOMAINS_FILE, 'a') as f:
f.write(f'{domain} OK\n')
# Update postmap
success, stdout, stderr = run_command(f'postmap {DOMAINS_FILE}')
if not success:
return False, f'Failed to update postmap: {stderr}'
# Reload postfix
success, stdout, stderr = run_command('systemctl reload postfix')
if not success:
return False, f'Failed to reload postfix: {stderr}'
return True, 'Domain added successfully'
def remove_domain(domain):
"""Remove domain from virtual domains"""
domains = get_domains()
if domain not in domains:
return False, 'Domain not found'
# Read current file and filter out the domain
lines = []
if os.path.exists(DOMAINS_FILE):
with open(DOMAINS_FILE, 'r') as f:
for line in f:
if not line.strip().startswith(domain + ' '):
lines.append(line)
# Write back to file
with open(DOMAINS_FILE, 'w') as f:
f.writelines(lines)
# Update postmap and reload
run_command(f'postmap {DOMAINS_FILE}')
run_command('systemctl reload postfix')
return True, 'Domain removed successfully'
def add_alias(email, destination):
"""Add email alias"""
if not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', email):
return False, 'Invalid email format'
# Add alias to file
with open(ALIASES_FILE, 'a') as f:
f.write(f'{email} {destination}\n')
# Update postmap and reload
run_command(f'postmap {ALIASES_FILE}')
run_command('systemctl reload postfix')
return True, 'Alias added successfully'
@app.route('/')
def index():
domains = get_domains()
aliases = get_aliases()
return render_template('index.html', domains=domains, aliases=aliases)
@app.route('/add_domain', methods=['POST'])
def add_domain_route():
domain = request.form.get('domain', '').strip()
if domain:
success, message = add_domain(domain)
if success:
flash(message, 'success')
else:
flash(message, 'error')
return redirect(url_for('index'))
@app.route('/remove_domain', methods=['POST'])
def remove_domain_route():
domain = request.form.get('domain', '').strip()
if domain:
success, message = remove_domain(domain)
if success:
flash(message, 'success')
else:
flash(message, 'error')
return redirect(url_for('index'))
@app.route('/add_alias', methods=['POST'])
def add_alias_route():
email = request.form.get('email', '').strip()
destination = request.form.get('destination', '').strip()
if email and destination:
success, message = add_alias(email, destination)
if success:
flash(message, 'success')
else:
flash(message, 'error')
return redirect(url_for('index'))
@app.route('/test_email', methods=['POST'])
def test_email():
from_email = request.form.get('from_email', '').strip()
to_email = request.form.get('to_email', '').strip()
subject = request.form.get('subject', 'Test Email')
if from_email and to_email:
cmd = f"echo 'Subject: {subject}\nFrom: {from_email}\nTo: {to_email}\n\nTest email sent from SMTP Panel at {datetime.now()}' | sendmail -t"
success, stdout, stderr = run_command(cmd)
if success:
flash('Test email sent successfully!', 'success')
else:
flash(f'Failed to send test email: {stderr}', 'error')
else:
flash('Please provide both from and to email addresses', 'error')
return redirect(url_for('index'))
@app.route('/logs')
def logs():
success, stdout, stderr = run_command('tail -50 /var/log/mail.log')
logs = stdout if success else 'Failed to read logs'
return render_template('logs.html', logs=logs)
@app.route('/dns_instructions/<domain>')
def dns_instructions(domain):
"""Show DNS instructions for a domain"""
# Get DKIM public key
dkim_key = ''
dkim_file = f'{DKIM_DIR}/{domain}/default.txt'
if os.path.exists(dkim_file):
with open(dkim_file, 'r') as f:
content = f.read()
# Extract the key part between quotes
match = re.search(r'"([^"]+)"', content)
if match:
dkim_key = match.group(1).replace(' ', '')
dns_records = {
'A': f'{domain} IN A 111.00.00.000',
'MX': f'{domain} IN MX 10 mail.seudominio.com.br.',
'SPF': f'{domain} IN TXT "v=spf1 ip4:111.00.00.000 include:mail.seudominio.com.br ~all"',
'DKIM': f'default._domainkey.{domain} IN TXT "v=DKIM1; k=rsa; p={dkim_key}"',
'DMARC': f'_dmarc.{domain} IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@{domain}"',
'PTR': '111.00.00.000 IN PTR mail.seudominio.com.br.'
}
return render_template('dns_instructions.html', domain=domain, dns_records=dns_records)
@app.route('/check_dns', methods=['POST'])
def check_dns():
"""Check DNS configuration for a domain"""
domain = request.form.get('domain', '').strip()
if not domain:
return jsonify({'error': 'Domain is required'})
results = {}
# Check A record
success, stdout, stderr = run_command(f'dig +short A {domain}')
results['A'] = {
'status': 'OK' if '111.00.00.000' in stdout else 'FAIL',
'value': stdout.strip(),
'expected': '111.00.00.000'
}
# Check MX record
success, stdout, stderr = run_command(f'dig +short MX {domain}')
results['MX'] = {
'status': 'OK' if 'mail.seudominio.com.br' in stdout else 'FAIL',
'value': stdout.strip(),
'expected': '10 mail.seudominio.com.br.'
}
# Check SPF record
success, stdout, stderr = run_command(f'dig +short TXT {domain}')
spf_found = any('v=spf1' in line for line in stdout.split('\n'))
results['SPF'] = {
'status': 'OK' if spf_found else 'FAIL',
'value': stdout.strip(),
'expected': 'v=spf1 ip4:111.00.00.000 include:mail.seudominio.com.br ~all'
}
# Check DKIM record
success, stdout, stderr = run_command(f'dig +short TXT default._domainkey.{domain}')
dkim_found = any('v=DKIM1' in line for line in stdout.split('\n'))
results['DKIM'] = {
'status': 'OK' if dkim_found else 'FAIL',
'value': stdout.strip(),
'expected': 'v=DKIM1; k=rsa; p=...'
}
# Check DMARC record
success, stdout, stderr = run_command(f'dig +short TXT _dmarc.{domain}')
dmarc_found = any('v=DMARC1' in line for line in stdout.split('\n'))
results['DMARC'] = {
'status': 'OK' if dmarc_found else 'FAIL',
'value': stdout.strip(),
'expected': 'v=DMARC1; p=quarantine; rua=mailto:dmarc@domain'
}
return jsonify(results)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=True)