So implementieren Sie einen einfachen E-Mail-Server mit Golang

PHPz
Freigeben: 2023-04-04 17:37:55
Original
1816 Leute haben es durchsucht

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
Nach dem Login kopieren

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)
    }
}
Nach dem Login kopieren

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)
}
Nach dem Login kopieren

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:

  • Zustand 0: Verarbeiten Sie den HELO-Befehl des Clients und geben Sie Status 1 ein.
  • Zustand 1: Verarbeiten Sie den MAIL-Befehl des Clients und geben Sie Status 2 ein.
  • Zustand 2: Verarbeiten Sie den Client RCPT-Befehl auf dem Client und wechselt in Status 3
  • Status 3: Warten darauf, dass der Client einen DATA-Befehl sendet oder einen HELO/QUIT-Befehl verarbeitet oder ein Fehler auftritt, und wechselt in den entsprechenden Status
  • Status 4: Empfängt E-Mail-Daten vom Client gesendet (mit „.“ am Ende), senden Sie eine E-Mail und geben Sie Status 1 ein

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()
Nach dem Login kopieren

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!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage