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
- The redirect mechanisms used above are not restricted to mailto and tel. You can use them to redirect to regular HTTP URLs as well.
- 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.