Skip to content

Commit 5f008a3

Browse files
committed
added mailify v.1.0.0
Signed-off-by: adarsh-jaiss <[email protected]>
1 parent a399fac commit 5f008a3

File tree

8 files changed

+617
-0
lines changed

8 files changed

+617
-0
lines changed

CODEOWNERS

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@Adarsh-jaiss

README.md

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Mailify
2+
3+
Mailify is a Go package for validating email addresses by checking their format, verifying the existence of MX records for the domain, and attempting to connect to the mail servers using SMTP.
4+
5+
## Installation
6+
7+
To install the package, run:
8+
9+
```sh
10+
go get github.com/adarsh-jaiss/mailify
11+
12+
```
13+
14+
## Usage
15+
16+
### Creating a Client
17+
18+
To create a new client, use the NewClient function:
19+
20+
```go
21+
client, err := mailify.NewClient("[email protected]")
22+
if err != nil {
23+
log.Fatalf("Failed to create mailify client: %v", err)
24+
}
25+
```
26+
27+
### Validating an Email Address
28+
29+
To validate an email address, use the ValidateEmail method:
30+
31+
```go
32+
result, err := client.ValidateEmail("[email protected]")
33+
if err != nil {
34+
log.Fatalf("Failed to validate email: %v", err)
35+
}
36+
37+
fmt.Println("Validation result:", client.FormatValidationResult("[email protected]", result))
38+
```
39+
40+
### Getting Mail Servers
41+
To get the mail servers for a domain, use the GetMailServers method:
42+
43+
```go
44+
mailServers, err := client.GetMailServers("example.com")
45+
if err != nil {
46+
log.Fatalf("Failed to get mail servers: %v", err)
47+
}
48+
49+
fmt.Println("Mail servers:", mailServers)
50+
```
51+
52+
To get the mail servers for a recipient email, use the GetMailServersFromReceipientEmail method:
53+
54+
```go
55+
56+
mailServers, err := client.GetMailServersFromReceipientEmail("[email protected]")
57+
if err != nil {
58+
log.Fatalf("Failed to get mail servers: %v", err)
59+
}
60+
61+
fmt.Println("Mail servers:", mailServers)
62+
```
63+
64+
### Example
65+
Here is a complete example demonstrating how to use the package : [check examples]()

client.go

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package mailify
2+
3+
//
4+
// Client represents an email client with a sender email address.
5+
type Client struct {
6+
SenderEmail string
7+
}
8+
9+
// NewClient creates a new Client instance with the provided sender email address.
10+
// It returns a pointer to the Client and an error, if any.
11+
//
12+
// Parameters:
13+
// - SenderEmail: A string representing the sender's email address.
14+
//
15+
// Returns:
16+
// - *Client: A pointer to the newly created Client instance.
17+
// - error: An error if there is any issue during the creation of the Client.
18+
func NewClient(SenderEmail string) (*Client, error) {
19+
return &Client{
20+
SenderEmail: SenderEmail,
21+
}, nil
22+
}
23+

examples/main.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"fmt"
6+
7+
"github.com/adarsh-jaiss/mailify"
8+
)
9+
10+
func main() {
11+
// Create a new mailguard client
12+
senderEmail := "[email protected]"
13+
receipientEmail := "[email protected]"
14+
15+
client, err := mailify.NewClient(senderEmail)
16+
if err != nil {
17+
log.Fatalf("Failed to create mailguard client: %v", err)
18+
}
19+
20+
// Get mail servers for a domain
21+
resp, err := client.GetMailServers("namanrai.tech")
22+
if err != nil {
23+
log.Fatalf("Failed to get mail servers: %v", err)
24+
}
25+
log.Println("Mail servers:", resp)
26+
27+
// Get mail servers for a recepient email
28+
res, err := client.GetMailServersFromReceipientEmail(receipientEmail)
29+
if err != nil {
30+
log.Fatalf("Failed to get mail servers: %v", err)
31+
}
32+
log.Println("Mail servers:", res)
33+
34+
// Validate an email address
35+
result, err := client.ValidateEmail(receipientEmail)
36+
if err!= nil {
37+
log.Fatalf("Failed to validate email: %v", err)
38+
}
39+
40+
fmt.Println("Validation result:", client.FormatValidationResult(receipientEmail,result))
41+
42+
}

go.mod

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/adarsh-jaiss/mailify
2+
3+
go 1.22.1

servers.go

+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
package mailify
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net"
7+
"strings"
8+
"time"
9+
)
10+
11+
// GetMailServers retrieves the mail servers (MX records) for a given domain.
12+
// It uses a custom DNS resolver that queries Google's public DNS server (8.8.8.8).
13+
14+
// Parameters:
15+
// - domain: The domain name for which to look up MX records.
16+
17+
// Returns:
18+
// - A slice of strings containing the mail server hostnames.
19+
// - An error if there was an issue looking up the MX records.
20+
21+
// Example:
22+
// mailServers, err := GetMailServers("example.com")
23+
// if err != nil {
24+
// log.Fatalf("Failed to get mail servers: %v", err)
25+
// }
26+
// fmt.Println("Mail servers:", mailServers)
27+
28+
func(c *Client) GetMailServers(domain string) ([]string, error) {
29+
// Use custom DNS resolver to query Google's public DNS server
30+
31+
resolver := net.Resolver{
32+
PreferGo: true,
33+
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
34+
d := net.Dialer{}
35+
return d.DialContext(ctx, network, "8.8.8.8:53") // Use Google DNS
36+
},
37+
}
38+
39+
// Lookup MX records for the domain
40+
mx, err := resolver.LookupMX(context.Background(), domain)
41+
// mx, err := net.LookupMX(domain)
42+
if err != nil {
43+
return nil, fmt.Errorf("error looking up MX records: %v", err)
44+
}
45+
46+
// Extract mail server hostnames
47+
var mailServers []string
48+
for _, record := range mx {
49+
mailServers = append(mailServers, strings.TrimSuffix(record.Host, "."))
50+
}
51+
52+
// Print mail servers
53+
// fmt.Printf("Found mail servers for %s: %v\n", domain, mailServers)
54+
return mailServers, nil
55+
}
56+
57+
// GetSMTPServer attempts to find an available SMTP server for the given mail server.
58+
// It performs a DNS lookup to get all IP addresses (both IPv4 and IPv6) associated with the mail server,
59+
// and then tries to connect to common SMTP ports (587, 25, 465) on each IP address.
60+
//
61+
// If a connection is successfully established, it returns the SMTP server details including
62+
// the server name, port, protocol, and IP address. If no available SMTP servers are found,
63+
// it returns an error.
64+
//
65+
// Parameters:
66+
// - mailServer: The domain name of the mail server to look up.
67+
//
68+
// Returns:
69+
// - *SMTPDetails: A struct containing the details of the SMTP server if found.
70+
// - error: An error if no available SMTP servers are found or if there is a lookup failure.
71+
func(c *Client) GetSMTPServer(mailServer string) (*SMTPDetails, error) {
72+
// Get all IPs (both IPv4 and IPv6)
73+
ips, err := net.LookupIP(mailServer)
74+
if err != nil {
75+
return nil, fmt.Errorf("failed to lookup IP for %s: %v", mailServer, err)
76+
}
77+
78+
// Try each IP address
79+
for _, ip := range ips {
80+
// Try common SMTP ports
81+
ports := []string{"587", "25", "465"}
82+
for _, port := range ports {
83+
// Format address based on IP version
84+
var address string
85+
if ip.To4() != nil {
86+
// IPv4
87+
address = fmt.Sprintf("%s:%s", ip.String(), port)
88+
} else {
89+
// IPv6 - wrap in square brackets
90+
address = fmt.Sprintf("[%s]:%s", ip.String(), port)
91+
}
92+
93+
// Set timeout for connection
94+
smtpTimeout := time.Duration(time.Second * 5)
95+
96+
// Try to connect
97+
conn, err := net.DialTimeout("tcp", address, smtpTimeout)
98+
if err != nil {
99+
continue
100+
}
101+
defer conn.Close()
102+
103+
return &SMTPDetails{
104+
Server: mailServer,
105+
Port: port,
106+
Protocol: "SMTP",
107+
IPAddress: ip.String(),
108+
}, nil
109+
}
110+
}
111+
return nil, fmt.Errorf("no available SMTP servers found for %s", mailServer)
112+
}
113+
114+
// GetMailServersFromReceipientEmail extracts the domain from the given email address
115+
// and retrieves the mail servers associated with that domain.
116+
//
117+
// Parameters:
118+
// email (string): The recipient's email address.
119+
//
120+
// Returns:
121+
// []string: A slice of mail server addresses.
122+
// error: An error object if there was an issue extracting the domain or retrieving the mail servers.
123+
func(c *Client) GetMailServersFromReceipientEmail(email string) ([]string, error) {
124+
// Extract domain from email address
125+
domain,err := c.ExtractDomainFromEmailAddress(email)
126+
if err != nil {
127+
return nil, fmt.Errorf("error extracting domain from email address: %v", err)
128+
}
129+
130+
return c.GetMailServers(domain)
131+
}

types.go

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package mailify
2+
3+
4+
// SMTPDetails holds the details required to connect to an SMTP server.
5+
type SMTPDetails struct {
6+
// Server is the address of the SMTP server.
7+
Server string
8+
// Port is the port number on which the SMTP server is listening.
9+
Port string
10+
// Protocol is the protocol used by the SMTP server (e.g., "SMTP", "SMTPS").
11+
Protocol string
12+
// UsedTLS indicates whether TLS is used for the connection.
13+
UsedTLS bool
14+
// IPAddress is the IP address of the SMTP server.
15+
IPAddress string
16+
}
17+
18+
// ValidationResult represents the result of an email validation check.
19+
type ValidationResult struct {
20+
// IsValid indicates whether the email address is valid.
21+
IsValid bool
22+
// IsCatchAll indicates whether the domain has a catch-all address.
23+
IsCatchAll bool
24+
// HasMX indicates whether the domain has MX records.
25+
HasMX bool
26+
// ErrorMessage contains any error message encountered during validation.
27+
ErrorMessage string
28+
// SMTPDetails contains the SMTP server details used for validation.
29+
SMTPDetails *SMTPDetails
30+
}
31+

0 commit comments

Comments
 (0)