Skip to content

Commit

Permalink
added mailify v.1.0.0
Browse files Browse the repository at this point in the history
Signed-off-by: adarsh-jaiss <its.adarshjaiss@gmail.com>
  • Loading branch information
Adarsh-jaiss committed Nov 9, 2024
1 parent a399fac commit 5f008a3
Show file tree
Hide file tree
Showing 8 changed files with 617 additions and 0 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@Adarsh-jaiss
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Mailify

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.

## Installation

To install the package, run:

```sh
go get github.com/adarsh-jaiss/mailify

```

## Usage

### Creating a Client

To create a new client, use the NewClient function:

```go
client, err := mailify.NewClient("sender@example.com")
if err != nil {
log.Fatalf("Failed to create mailify client: %v", err)
}
```

### Validating an Email Address

To validate an email address, use the ValidateEmail method:

```go
result, err := client.ValidateEmail("recipient@example.com")
if err != nil {
log.Fatalf("Failed to validate email: %v", err)
}

fmt.Println("Validation result:", client.FormatValidationResult("recipient@example.com", result))
```

### Getting Mail Servers
To get the mail servers for a domain, use the GetMailServers method:

```go
mailServers, err := client.GetMailServers("example.com")
if err != nil {
log.Fatalf("Failed to get mail servers: %v", err)
}

fmt.Println("Mail servers:", mailServers)
```

To get the mail servers for a recipient email, use the GetMailServersFromReceipientEmail method:

```go

mailServers, err := client.GetMailServersFromReceipientEmail("recipient@example.com")
if err != nil {
log.Fatalf("Failed to get mail servers: %v", err)
}

fmt.Println("Mail servers:", mailServers)
```

### Example
Here is a complete example demonstrating how to use the package : [check examples]()
23 changes: 23 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package mailify

//
// Client represents an email client with a sender email address.
type Client struct {
SenderEmail string
}

// NewClient creates a new Client instance with the provided sender email address.
// It returns a pointer to the Client and an error, if any.
//
// Parameters:
// - SenderEmail: A string representing the sender's email address.
//
// Returns:
// - *Client: A pointer to the newly created Client instance.
// - error: An error if there is any issue during the creation of the Client.
func NewClient(SenderEmail string) (*Client, error) {
return &Client{
SenderEmail: SenderEmail,
}, nil
}

42 changes: 42 additions & 0 deletions examples/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package main

import (
"log"
"fmt"

"github.com/adarsh-jaiss/mailify"
)

func main() {
// Create a new mailguard client
senderEmail := "its.adarshjaiss@gmail.com"
receipientEmail := "hello@namanrai.tech"

client, err := mailify.NewClient(senderEmail)
if err != nil {
log.Fatalf("Failed to create mailguard client: %v", err)
}

// Get mail servers for a domain
resp, err := client.GetMailServers("namanrai.tech")
if err != nil {
log.Fatalf("Failed to get mail servers: %v", err)
}
log.Println("Mail servers:", resp)

// Get mail servers for a recepient email
res, err := client.GetMailServersFromReceipientEmail(receipientEmail)
if err != nil {
log.Fatalf("Failed to get mail servers: %v", err)
}
log.Println("Mail servers:", res)

// Validate an email address
result, err := client.ValidateEmail(receipientEmail)
if err!= nil {
log.Fatalf("Failed to validate email: %v", err)
}

fmt.Println("Validation result:", client.FormatValidationResult(receipientEmail,result))

}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/adarsh-jaiss/mailify

go 1.22.1
131 changes: 131 additions & 0 deletions servers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package mailify

import (
"context"
"fmt"
"net"
"strings"
"time"
)

// GetMailServers retrieves the mail servers (MX records) for a given domain.
// It uses a custom DNS resolver that queries Google's public DNS server (8.8.8.8).

// Parameters:
// - domain: The domain name for which to look up MX records.

// Returns:
// - A slice of strings containing the mail server hostnames.
// - An error if there was an issue looking up the MX records.

// Example:
// mailServers, err := GetMailServers("example.com")
// if err != nil {
// log.Fatalf("Failed to get mail servers: %v", err)
// }
// fmt.Println("Mail servers:", mailServers)

func(c *Client) GetMailServers(domain string) ([]string, error) {
// Use custom DNS resolver to query Google's public DNS server

resolver := net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
d := net.Dialer{}
return d.DialContext(ctx, network, "8.8.8.8:53") // Use Google DNS
},
}

// Lookup MX records for the domain
mx, err := resolver.LookupMX(context.Background(), domain)
// mx, err := net.LookupMX(domain)
if err != nil {
return nil, fmt.Errorf("error looking up MX records: %v", err)
}

// Extract mail server hostnames
var mailServers []string
for _, record := range mx {
mailServers = append(mailServers, strings.TrimSuffix(record.Host, "."))
}

// Print mail servers
// fmt.Printf("Found mail servers for %s: %v\n", domain, mailServers)
return mailServers, nil
}

// GetSMTPServer attempts to find an available SMTP server for the given mail server.
// It performs a DNS lookup to get all IP addresses (both IPv4 and IPv6) associated with the mail server,
// and then tries to connect to common SMTP ports (587, 25, 465) on each IP address.
//
// If a connection is successfully established, it returns the SMTP server details including
// the server name, port, protocol, and IP address. If no available SMTP servers are found,
// it returns an error.
//
// Parameters:
// - mailServer: The domain name of the mail server to look up.
//
// Returns:
// - *SMTPDetails: A struct containing the details of the SMTP server if found.
// - error: An error if no available SMTP servers are found or if there is a lookup failure.
func(c *Client) GetSMTPServer(mailServer string) (*SMTPDetails, error) {
// Get all IPs (both IPv4 and IPv6)
ips, err := net.LookupIP(mailServer)
if err != nil {
return nil, fmt.Errorf("failed to lookup IP for %s: %v", mailServer, err)
}

// Try each IP address
for _, ip := range ips {
// Try common SMTP ports
ports := []string{"587", "25", "465"}
for _, port := range ports {
// Format address based on IP version
var address string
if ip.To4() != nil {
// IPv4
address = fmt.Sprintf("%s:%s", ip.String(), port)
} else {
// IPv6 - wrap in square brackets
address = fmt.Sprintf("[%s]:%s", ip.String(), port)
}

// Set timeout for connection
smtpTimeout := time.Duration(time.Second * 5)

// Try to connect
conn, err := net.DialTimeout("tcp", address, smtpTimeout)
if err != nil {
continue
}
defer conn.Close()

return &SMTPDetails{
Server: mailServer,
Port: port,
Protocol: "SMTP",
IPAddress: ip.String(),
}, nil
}
}
return nil, fmt.Errorf("no available SMTP servers found for %s", mailServer)
}

// GetMailServersFromReceipientEmail extracts the domain from the given email address
// and retrieves the mail servers associated with that domain.
//
// Parameters:
// email (string): The recipient's email address.
//
// Returns:
// []string: A slice of mail server addresses.
// error: An error object if there was an issue extracting the domain or retrieving the mail servers.
func(c *Client) GetMailServersFromReceipientEmail(email string) ([]string, error) {
// Extract domain from email address
domain,err := c.ExtractDomainFromEmailAddress(email)
if err != nil {
return nil, fmt.Errorf("error extracting domain from email address: %v", err)
}

return c.GetMailServers(domain)
}
31 changes: 31 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package mailify


// SMTPDetails holds the details required to connect to an SMTP server.
type SMTPDetails struct {
// Server is the address of the SMTP server.
Server string
// Port is the port number on which the SMTP server is listening.
Port string
// Protocol is the protocol used by the SMTP server (e.g., "SMTP", "SMTPS").
Protocol string
// UsedTLS indicates whether TLS is used for the connection.
UsedTLS bool
// IPAddress is the IP address of the SMTP server.
IPAddress string
}

// ValidationResult represents the result of an email validation check.
type ValidationResult struct {
// IsValid indicates whether the email address is valid.
IsValid bool
// IsCatchAll indicates whether the domain has a catch-all address.
IsCatchAll bool
// HasMX indicates whether the domain has MX records.
HasMX bool
// ErrorMessage contains any error message encountered during validation.
ErrorMessage string
// SMTPDetails contains the SMTP server details used for validation.
SMTPDetails *SMTPDetails
}

Loading

0 comments on commit 5f008a3

Please sign in to comment.