Here are two ways to redirect an URL to an email address (mailto:) or a phone number (tel:).

1. Using http.Redirect

The Redirect function from the http package redirects from one URL to another. To use this function to redirect to a mailto: URL, just call the function from the handler that processes the original/source URL.

Function signature

func Redirect(w ResponseWriter, r *Request, url string, code int)

Quick Snippet

http.Redirect(w, r, "mailto:abcdef@test.com", http.StatusMovedPermanently)

http.Redirect(w, r, "tel:1234567890", http.StatusMovedPermanently)

Example 1a: Quick example to show where to call Redirect

In the following example, URL /email/ is 301-redirected to mailto:someemail@test.com, /phone/ is 301-redirected to tel:0123456789

package main

import (
    "net/http"
)

func main() {
    http.HandleFunc("/email/", handleEmail)
    http.HandleFunc("/phone/", handlePhone)
    http.ListenAndServe(":8888", nil)
}

func handleEmail(rw http.ResponseWriter, r *http.Request) {
    http.Redirect(rw, r, "mailto:someemail@test.com", http.StatusMovedPermanently)
}

func handlePhone(rw http.ResponseWriter, r *http.Request) {
    http.Redirect(rw, r, "tel:0123456789", http.StatusMovedPermanently)
}

Example 1b: Redirect to Email/Phone based on URL

This is a more complex example. Endpoints /email/ and /phone/ now take user input.

For example, /email/abc@test.com redirects to mailto:abc@test.com

/phone/+01123456789 redirects to +01123456789

Note that the user input validation is not up to production standards — its security is not guaranteed.

package main

import (
    "fmt"
    "log"
    "regexp"
    "net/http"
)

var (
    emailRe = regexp.MustCompile(`^\/email\/(.*@.*\..*)/?$`)    // Insecure: do not use this in production
    phoneRe = regexp.MustCompile(`^\/phone\/(\+?\d+)/?$`)
)


func main() {
    http.HandleFunc("/email/", handleEmail)
    http.HandleFunc("/phone/", handlePhone)
    http.ListenAndServe(":8888", nil)
}

func handleEmail(rw http.ResponseWriter, r *http.Request) {
    log.Println("URL: ", r.URL.Path)

    matches := emailRe.FindStringSubmatch(r.URL.Path)

    if len(matches) != 2 {
        http.Error(rw, fmt.Sprintf("Invalid request. URL: %v", r.URL.Path), http.StatusBadRequest)
        return
    }

    dst := "mailto: " + matches[1]

    log.Printf("Redirecting from %v to %v", r.URL.Path, dst)
    http.Redirect(rw, r, dst, http.StatusMovedPermanently)
}

func handlePhone(rw http.ResponseWriter, r *http.Request) {
    log.Println("URL: ", r.URL.Path)

    matches := phoneRe.FindStringSubmatch(r.URL.Path)

    if len(matches) != 2 {
        http.Error(rw, fmt.Sprintf("Invalid request. URL: %v", r.URL.Path), http.StatusBadRequest)
        return
    }

    dst := "tel: " + matches[1]

    log.Printf("Redirecting from %v to %v", r.URL.Path, dst)
    http.Redirect(rw, r, dst, http.StatusMovedPermanently)
}

2. Add a Location Header

Another way to redirect URLs is by using the Location header.

I don’t recommend this solution because it is not as self-explanatory as using http.Redirect.

Anyway, I’m putting this solution here for completeness. Also if you come from a PHP background, this will seem familiar.

Quick snippet

rw.Header().Set("Location", "mailto:abctest@test.com")
rw.WriteHeader(http.StatusMovedPermanently)

rw is a ResponseWriter.

See it in action in the example below.

Example 2a

In the following example, handler function, handleEmail, redirects /email/ to mailto:someemail@test.com

handlePhone redirects /phone/ to tel:0123456789

package main

import (
    "net/http"
)

func main() {
    http.HandleFunc("/email/", handleEmail)
    http.HandleFunc("/phone/", handlePhone)
    http.ListenAndServe(":8888", nil)
}

func handleEmail(rw http.ResponseWriter, r *http.Request) {
    rw.Header().Set("Location", "mailto:someemail@test.com")
    rw.WriteHeader(http.StatusMovedPermanently)
}

func handlePhone(rw http.ResponseWriter, r *http.Request) {
    rw.Header().Set("Location", "tel:0123456789")
    rw.WriteHeader(http.StatusMovedPermanently)
}

Discussions

  1. The redirect mechanisms used above are not restricted to mailto and tel. You can use them to redirect to regular HTTP URLs as well.
  2. If the goal is spam prevention, solution found in Example 1b may not be helpful because the email address is still visible from the URL (e.g. /email/abc@test.com). This might not prevent bots from recognizing the pattern as an email address. For stateless implementation, consider obfuscating the email address and the endpoint, e.g. /m/com/test/abc or /email/abc/test.com or /m/?h=abc&d=test&tld=com. For stateful solution, just hash and store the email address. Of course, none of this helps if the bot follows the redirection.