Spaces:
Paused
Paused
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import ssl
|
| 3 |
+
from aiosmtpd.controller import Controller
|
| 4 |
+
from aiosmtpd.handlers import Sink
|
| 5 |
+
from aiosmtpd.smtp import SMTP, AuthResult, LoginPassword
|
| 6 |
+
from email.policy import default
|
| 7 |
+
from typing import Optional
|
| 8 |
+
|
| 9 |
+
# Configure logging
|
| 10 |
+
logging.basicConfig(level=logging.INFO)
|
| 11 |
+
logger = logging.getLogger("smtp_server")
|
| 12 |
+
|
| 13 |
+
# SMTP Server Configuration
|
| 14 |
+
SMTP_HOST = "0.0.0.0" # Bind to all interfaces
|
| 15 |
+
SMTP_PORT = 587 # Standard SMTP submission port
|
| 16 |
+
TLS_CERTFILE = "cert.pem" # Path to your SSL certificate
|
| 17 |
+
TLS_KEYFILE = "key.pem" # Path to your SSL private key
|
| 18 |
+
|
| 19 |
+
# Authentication Credentials (for demo purposes; use a secure vault in production)
|
| 20 |
+
VALID_USERS = {
|
| 21 |
+
"user1": "password1",
|
| 22 |
+
"user2": "password2",
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
class AuthenticatedSMTPHandler(Sink):
|
| 26 |
+
async def handle_AUTH(self, server: SMTP, args: str, mechanism: str) -> Optional[AuthResult]:
|
| 27 |
+
if mechanism.upper() != "LOGIN":
|
| 28 |
+
return AuthResult(success=False, handled=False)
|
| 29 |
+
return None
|
| 30 |
+
|
| 31 |
+
async def handle_AUTH_LOGIN(self, server: SMTP, args: str) -> Optional[AuthResult]:
|
| 32 |
+
try:
|
| 33 |
+
username, password = args.split()
|
| 34 |
+
if username in VALID_USERS and VALID_USERS[username] == password:
|
| 35 |
+
return AuthResult(success=True, auth_data=LoginPassword(username, password))
|
| 36 |
+
else:
|
| 37 |
+
return AuthResult(success=False, message="Invalid credentials")
|
| 38 |
+
except Exception as e:
|
| 39 |
+
logger.error(f"Authentication error: {e}")
|
| 40 |
+
return AuthResult(success=False, message="Authentication failed")
|
| 41 |
+
|
| 42 |
+
async def handle_DATA(self, server: SMTP, session, envelope):
|
| 43 |
+
# Log the received email
|
| 44 |
+
logger.info(f"Received email from: {envelope.mail_from}")
|
| 45 |
+
logger.info(f"Recipients: {envelope.rcpt_tos}")
|
| 46 |
+
logger.info(f"Message data:\n{envelope.content.decode('utf-8')}")
|
| 47 |
+
return "250 Message accepted for delivery"
|
| 48 |
+
|
| 49 |
+
def start_smtp_server():
|
| 50 |
+
# Create SSL context for TLS
|
| 51 |
+
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
| 52 |
+
ssl_context.load_cert_chain(TLS_CERTFILE, TLS_KEYFILE)
|
| 53 |
+
|
| 54 |
+
# Create the SMTP handler
|
| 55 |
+
handler = AuthenticatedSMTPHandler()
|
| 56 |
+
|
| 57 |
+
# Start the SMTP server with TLS and authentication
|
| 58 |
+
controller = Controller(
|
| 59 |
+
handler,
|
| 60 |
+
hostname=SMTP_HOST,
|
| 61 |
+
port=SMTP_PORT,
|
| 62 |
+
enable_SMTPUTF8=True,
|
| 63 |
+
ssl_context=ssl_context,
|
| 64 |
+
auth_required=True,
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
logger.info(f"Starting SMTP server on {SMTP_HOST}:{SMTP_PORT} with TLS and authentication...")
|
| 68 |
+
controller.start()
|
| 69 |
+
try:
|
| 70 |
+
# Keep the server running
|
| 71 |
+
while True:
|
| 72 |
+
pass
|
| 73 |
+
except KeyboardInterrupt:
|
| 74 |
+
logger.info("Shutting down SMTP server...")
|
| 75 |
+
controller.stop()
|
| 76 |
+
|
| 77 |
+
if __name__ == "__main__":
|
| 78 |
+
start_smtp_server()
|