如何通过代码实现SMTP服务器直接向其他服务器发送邮件
直接通过MTA(邮件传输代理)向远程SMTP服务器发送邮件的实现思路与代码
Got it, I totally get your frustration—every search result keeps pointing you to client-side SMTP setups, but you want the server-to-server MTA logic instead. Let's dive into what you need.
核心思路:MTA-to-MTA的SMTP交互
When an SMTP server sends mail to another server, it follows the standard MTA workflow:
- Step 1: Resolve the target domain's MX records — Use DNS to find which SMTP servers are responsible for accepting mail for the recipient's email domain.
- Step 2: Establish a TCP connection — Connect to the highest-priority MX server (lower priority number = higher priority) on port 25 (the standard MTA port; some use 587 for submission, but 25 is for server-to-server).
- Step 3: Perform SMTP handshake — Send
EHLO(orHELO) to identify your server, then negotiate TLS if supported. - Step 4: Send envelope details — Use
MAIL FROMandRCPT TOto specify the sender and recipient. - Step 5: Transmit the email content — Send the
DATAcommand, followed by the full email headers and body, ending with a single.on a line. - Step 6: Close the session — Send
QUITto terminate the connection.
常用的SMTP服务器/MTA库
Depending on your language, these libraries handle most low-level SMTP protocol work for you:
- Python:
smtplib(built-in) can be repurposed for MTA-to-MTA sending (as shown below)aiosmtpd— A full-featured async SMTP server framework, ideal if you're building your own MTA that needs to receive and forward mail
- Node.js:
nodemailer— Configure it to skip specifying a fixed SMTP host, and it'll automatically resolve MX records for the recipient domainsmtp-server— Build your own MTA with full control over incoming/outgoing mail flow
- Go:
net/smtp(standard library) combined withnet/dnsto resolve MX recordsgithub.com/emersion/go-smtp— A robust, extensible SMTP server implementation
Python代码示例:直接发送到目标MX服务器
Here's a working snippet that skips the "client connects to own SMTP server" step and goes straight to the recipient's MX server:
import smtplib import dns.resolver from email.mime.text import MIMEText def send_mta_to_mta(sender: str, recipient: str, subject: str, body: str): # Resolve recipient domain's MX records try: recipient_domain = recipient.split("@")[1] mx_records = dns.resolver.resolve(recipient_domain, "MX") except (IndexError, dns.resolver.NXDOMAIN, dns.resolver.NoAnswer) as e: print(f"Failed to resolve MX records: {str(e)}") return # Pick the highest-priority MX server mx_server = sorted(mx_records, key=lambda r: r.preference)[0].exchange.to_text() # Build the email message msg = MIMEText(body) msg["From"] = sender msg["To"] = recipient msg["Subject"] = subject # Connect and send try: with smtplib.SMTP(mx_server, 25, timeout=30) as server: # EHLO to initiate session server.ehlo() # Enable TLS if supported (most modern MTAs require this) if server.has_extn("STARTTLS"): server.starttls() server.ehlo() # Re-EHLO after TLS upgrade # Send the email server.sendmail(sender, recipient, msg.as_string()) print("Email sent successfully via target MX server!") except Exception as e: print(f"Failed to send email: {str(e)}") # Example usage send_mta_to_mta( sender="your-server@your-domain.com", recipient="user@target-domain.com", subject="Test MTA-to-MTA Email", body="This email was sent directly to the recipient's MX server, no intermediate SMTP client required!" )
Critical Notes for Production
- Port 25 Restrictions: Most cloud providers (AWS, GCP, Azure) block port 25 by default to prevent spam. You'll need to request a lift on this restriction or use port 587 for submission (though some MTAs only accept server-to-server traffic on 25).
- Reverse DNS (PTR): Your server's public IP must have a valid PTR record pointing to your domain. Without this, most MTAs will mark your mail as spam or reject it outright.
- SPF/DKIM/DMARC: Set up these DNS records for your sending domain to improve deliverability and prevent your mail from being flagged as spam.
- Error Handling: The example above has basic error handling, but in production you'll need to handle retries for transient failures, MX record fallbacks, and SMTP error codes (e.g.,
550= recipient rejected,450= temporary failure).
内容的提问来源于stack exchange,提问作者monty
相关产品推荐
相关产品推荐

