Mit der Entwicklung und Popularisierung des Internets ist E-Mail zu einem unverzichtbaren Bestandteil des Lebens der Menschen geworden. In diesem Artikel wird erläutert, wie Sie mit der Programmiersprache Golang einen einfachen E-Mail-Server implementieren.
1. Umgebungseinrichtung
Zuerst müssen Sie lokal eine Golang-Entwicklungsumgebung einrichten. Nach der Installation von Golang müssen Sie GOPATH festlegen. Diese Umgebungsvariable gibt das Arbeitsverzeichnis von Golang an. Alle in diesem Verzeichnis erstellten Dateien gelten als Quellcode von Golang.
Als nächstes installieren Sie die POP3- und SMTP-Bibliotheken mit den folgenden Befehlen:
go get github.com/jordan-wright/email go get github.com/beego/mux
Die beiden oben genannten Bibliotheken werden zum Senden von E-Mails bzw. zum Bearbeiten von HTTP-Anfragen verwendet.
2. POP3-Server implementieren
POP3 ist ein E-Mail-Empfangsprotokoll. E-Mails können mithilfe des POP3-Protokolls heruntergeladen werden. Um den POP3-Server zu implementieren, müssen wir den TCP-Server in Golang schreiben. In Golang können Sie das Paket „net“ verwenden, um die TCP-Serverentwicklung zu implementieren.
Das Folgende ist ein einfacher POP3-Servercode:
package main import ( "bufio" "fmt" "net" "strings" ) func handlePOP3(conn net.Conn) { fmt.Fprintf(conn, "+OK POP3 ready\r\n") scanner := bufio.NewScanner(conn) for scanner.Scan() { command := scanner.Text() if strings.HasPrefix(command, "QUIT") { fmt.Fprintf(conn, "+OK Bye\r\n") conn.Close() return } fmt.Fprintf(conn, "-ERR unknown command\r\n") } } func main() { listener, err := net.Listen("tcp", ":110") if err != nil { fmt.Println("Error listening:", err.Error()) return } defer listener.Close() fmt.Println("Listening on :110") for { conn, err := listener.Accept() if err != nil { fmt.Println("Error accepting connection:", err.Error()) return } go handlePOP3(conn) } }
Der obige Code überwacht lokal Port 110 (POP3-Standardport). Wenn ein Client eine Verbindung herstellt, wird eine Goroutine gestartet, um die Verbindung zu verwalten. Alle vom POP3-Server empfangenen Befehle sind Zeichenfolgen, daher verwenden wir den vom bufio-Paket bereitgestellten Scanner, um die Befehle zu analysieren.
In der handlePOP3-Funktion senden wir zunächst „+OK POP3 bereit“ an den Client, um anzuzeigen, dass der Server bereit ist. Dann liest es kontinuierlich die vom Client gesendeten Befehle in einer Schleife. Wenn es auf einen „QUIT“-Befehl stößt, sendet es „+OK Bye“, um die Sitzung zu beenden und die Verbindung zu schließen. Wenn ein weiterer unbekannter Befehl empfangen wird, senden Sie „-ERR unbekannter Befehl“, um dem Client mitzuteilen, dass der Befehl ungültig ist.
3. SMTP-Server implementieren
SMTP ist ein E-Mail-Versandprotokoll. E-Mails können über das SMTP-Protokoll an den Mailserver gesendet werden. Um den SMTP-Server zu implementieren, müssen wir Code hinzufügen, der auf dem POP3-Server basiert, um SMTP-Befehle zu verarbeiten.
Das Folgende ist ein einfacher SMTP-Servercode:
package main import ( "fmt" "net" "net/mail" "net/smtp" ) func handlePOP3(conn net.Conn) { // ... } func handleSMTP(conn net.Conn) { fmt.Fprintf(conn, "220 localhost SMTP Ready\r\n") state := 0 var from, to, data string for { buf := make([]byte, 1024) _, err := conn.Read(buf) if err != nil { fmt.Println("Error reading:", err.Error()) return } line := string(buf) switch state { case 0: if line[:4] != "HELO" { fmt.Fprintf(conn, "500 Error: bad command sequence\r\n") continue } fmt.Fprintf(conn, "250 localhost\r\n") state = 1 case 1: if line[:4] != "MAIL" { fmt.Fprintf(conn, "500 Error: bad command sequence\r\n") continue } from = line[5 : len(line)-2] fmt.Fprintf(conn, "250 OK\r\n") state = 2 case 2: if line[:4] != "RCPT" { fmt.Fprintf(conn, "500 Error: bad command sequence\r\n") continue } to = line[5 : len(line)-2] fmt.Fprintf(conn, "250 OK\r\n") state = 3 case 3: if line[:4] == "DATA" { fmt.Fprintf(conn, "354 End data with <CR><LF>.<CR><LF>\r\n") state = 4 } else if line[:4] == "HELO" { fmt.Fprintf(conn, "250 localhost\r\n") } else { fmt.Fprintf(conn, "500 Error: bad command sequence\r\n") } case 4: if line[:3] == "QUIT" { fmt.Fprintf(conn, "221 Bye\r\n") conn.Close() return } if line == ".\r\n" { fmt.Fprintf(conn, "250 OK: message accepted\r\n") msg, _ := mail.ReadMessage(strings.NewReader(data)) smtp.SendMail("localhost:25", nil, "test@test.com", []string{to}, []byte(data)) state = 1 } else { data += line } } } } func main() { // ... router := mux.NewRouter() router.HandleFunc("/pop3", handlePOP3) router.HandleFunc("/smtp", handleSMTP) http.ListenAndServe(":8080", router) }
Der obige Code überwacht lokal Port 25 (SMTP-Standardport). Wenn ein Client eine Verbindung herstellt, wird eine Goroutine gestartet, um die Verbindung zu verwalten. Alle vom SMTP-Server empfangenen Befehle sind ebenfalls Zeichenfolgen. Daher verwenden wir zum Lesen der Befehle die vom Net-Paket bereitgestellte Conn.Read-Methode.
In der handleSMTP-Funktion senden wir zunächst „220 localhost SMTP Ready“ an den Client, um anzuzeigen, dass der SMTP-Server bereit ist. Pflegen Sie dann eine Zustandsmaschine, um den E-Mail-Versandprozess abzuwickeln:
Wenn ein ungültiger Befehl empfangen wird, wird „500 Fehler: fehlerhafte Befehlssequenz“ gesendet, um dem Client mitzuteilen, dass der Befehl ungültig ist . Wenn ein QUIT-Befehl empfangen wird, wird „221 Bye“ gesendet, um das Ende der Sitzung anzuzeigen und die Verbindung zu schließen. In Status 4 verwenden wir das Paket „net/mail“ zum Parsen von E-Mail-Daten und das Paket „net/smtp“ zum Senden von E-Mails.
4. Testen
Der mit dem obigen Code implementierte Postfachserver ist nur ein einfaches Beispiel. Wenn er in einer tatsächlichen Produktionsumgebung verwendet werden soll, sind viele Aspekte des Testens und der Optimierung erforderlich. Das Folgende ist ein einfacher, in Python geschriebener SMTP-Client-Code, mit dem Sie E-Mails an unseren SMTP-Server senden und testen können, ob der SMTP-Server ordnungsgemäß funktioniert:
import smtplib server = smtplib.SMTP('localhost', 25) server.ehlo() server.mail('test@test.com') server.rcpt('test1@test.com') server.data('Subject: Test Mail\n\nThis is a test email.\n') server.quit()
5. Zusammenfassung
In diesem Artikel wird die Verwendung der Programmiersprache Golang vorgestellt um einen einfachen E-Mail-Server zu implementieren. Die Verwendung von Golang zum Schreiben von SMTP/POP3-Servercode ist leicht zu verstehen und zu erweitern. Gleichzeitig kann die Coroutine-Funktion von Golang eine hohe Parallelität unterstützen, was sich sehr gut für die Entwicklung von Netzwerkprogrammen eignet.
Das obige ist der detaillierte Inhalt vonSo implementieren Sie einen einfachen E-Mail-Server mit Golang. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!