package alps import ( "fmt" "net" "net/url" "strings" ) func discoverTCP(service, name string) (string, error) { _, addrs, err := net.LookupSRV(service, "tcp", name) if dnsErr, ok := err.(*net.DNSError); ok { if dnsErr.IsTemporary { return "", err } } else if err != nil { return "", err } if len(addrs) == 0 { return "", nil } addr := addrs[0] target := strings.TrimSuffix(addr.Target, ".") if target == "" { return "", nil } return fmt.Sprintf("%v:%v", target, addr.Port), nil } // discoverIMAP performs a DNS-based IMAP service discovery, as defined in // RFC 6186 section 3.2. func discoverIMAP(domain string) (*url.URL, error) { imapsHost, err := discoverTCP("imaps", domain) if err != nil { return nil, err } if imapsHost != "" { return &url.URL{Scheme: "imaps", Host: imapsHost}, nil } imapHost, err := discoverTCP("imap", domain) if err != nil { return nil, err } if imapHost != "" { return &url.URL{Scheme: "imap", Host: imapHost}, nil } return nil, fmt.Errorf("IMAP service discovery not configured for domain %q", domain) } // discoverSMTP performs a DNS-based SMTP submission service discovery, as // defined in RFC 6186 section 3.1. RFC 8314 section 5.1 adds a new service for // SMTP submission with implicit TLS. func discoverSMTP(domain string) (*url.URL, error) { smtpsHost, err := discoverTCP("submissions", domain) if err != nil { return nil, err } if smtpsHost != "" { return &url.URL{Scheme: "smtps", Host: smtpsHost}, nil } smtpHost, err := discoverTCP("submission", domain) if err != nil { return nil, err } if smtpHost != "" { return &url.URL{Scheme: "smtp", Host: smtpHost}, nil } return nil, fmt.Errorf("SMTP service discovery not configured for domain %q", domain) }