smtp.Dial은 자신의 주소로 새 연결을 엽니다. HTTP CONNECT 프록시를 통해 연결을 얻은 뒤에는 그 기존 스트림을 대신 smtp.NewClient에 넘깁니다.

제출 포트에서 STARTTLS를 요구하는 SMTP 서버라면 인계는 다음과 같습니다.

func smtpOverTunnel(conn net.Conn, mailHost string) (*smtp.Client, error) {
    client, err := smtp.NewClient(conn, mailHost)
    if err != nil {
        conn.Close()
        return nil, err
    }
    err = client.StartTLS(&tls.Config{
        ServerName: mailHost,
        MinVersion: tls.VersionTLS12,
    })
    if err != nil {
        client.Close()
        return nil, err
    }
    return client, nil
}

패키지는 net, net/smtp, crypto/tls입니다. 호출자는 원하는 SMTP 호스트와 포트에 이미 연결된 터널을 제공하며, 프록시의 CONNECT 교환은 완료된 상태입니다. 프록시에 TCP만 여는 것으로는 충분하지 않습니다. HTTP 응답은 SMTP 인사가 아닙니다.

mailHost는 SMTP 서버의 호스트 이름이며 포트는 포함하지 않습니다. SMTP 인증과 인증서 검증에는 그 동일성을 유지하세요. HTTPS 프록시로 향하는 TLS 연결은 경로의 다른 구간을 보호합니다.

반환된 클라이언트는 애플리케이션의 기존 SMTP 인증과 메일 트랜잭션에 바로 쓸 수 있습니다. 끝나면 닫으세요. 다이얼, CONNECT 및 이후 프로토콜 작업은 애플리케이션의 마감 정책으로 제한하세요.

프록시는 선택한 메일 포트로의 CONNECT를 허용해야 합니다. 일부는 443 포트의 HTTPS 대상으로만 제한합니다. 암묵적 TLS SMTP라면 STARTTLS를 내보내는 대신 NewClient를 호출하기 전에 대상의 TLS 세션을 설정하세요.

관련 글