Skip to content

Commit

Permalink
Add some(what) working code and some documentation
Browse files Browse the repository at this point in the history
Initial commit.

Successfully pulls a message from an inbox that actually contains a
message.

Not perfect; there's some duplication which could be simplified, and
there's the issue of panics when there are no messages available.

But it's late, and I'm off to sleep now. Good night.
  • Loading branch information
StevenMaude committed Nov 8, 2016
0 parents commit bffef80
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 0 deletions.
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# go-mailin8

Display the latest mail from a temporary Mailinator email address, at
the command line.

Useful for getting confirmation emails for throwaway purposes, or for
testing.

This is a version of a [bash script I
made](https://gist.github.com/StevenMaude/914e9187c09027866fe88958798acb7e)
that uses [jq](https://stedolan.github.io/jq/). However, this Go version
requires no other dependencies.

## Build

`go build`

## Usage

1. Send, or get an email sent to a Mailinator email address of your
choosing.
2. Note the local-part (the part before @, e.g.
`[email protected]`).
3. Run `go-mailin8 <local-part of email address>`

## Notes

NB: you may get unpredictable results from the server if you run this
too often in a short time. See TODO.

## TODO:

* Fix panics on no messages.
* Consider introducing slight pauses between requests to try and
improve reliability.
* Possibly consider selecting other than latest message (though outside
of my original use case).
165 changes: 165 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package main

import (
"encoding/json"
"fmt"
"net/http"
"os"
)

/* Full mail struct for posterity; generated from https://mholt.github.io/json-to-go/
type AutoGenerated struct {
Data struct {
Fromfull string `json:"fromfull"`
Headers struct {
MimeVersion string `json:"mime-version"`
Date string `json:"date"`
Subject string `json:"subject"`
XSgEid string `json:"x-sg-eid"`
MessageID string `json:"message-id"`
Received string `json:"received"`
From string `json:"from"`
ContentType string `json:"content-type"`
To string `json:"to"`
DkimSignature string `json:"dkim-signature"`
} `json:"headers"`
Subject string `json:"subject"`
RequestID string `json:"requestId"`
Parts []struct {
Headers struct {
ContentTransferEncoding string `json:"content-transfer-encoding"`
ContentType string `json:"content-type"`
} `json:"headers"`
Body string `json:"body"`
} `json:"parts"`
From string `json:"from"`
Origfrom string `json:"origfrom"`
To string `json:"to"`
ID string `json:"id"`
Time int64 `json:"time"`
SecondsAgo int `json:"seconds_ago"`
} `json:"data"`
} */

type mail struct {
Data struct {
Subject string `json:"subject"`
Parts []struct {
Body string `json:"body"`
} `json:"parts"`
From string `json:"from"`
} `json:"data"`
}

// TODO: consider dropping most of this. Can get from the message itself.
type mailboxDetails struct {
PublicMsgs []struct {
FromFull string `json:"fromfull"`
Subject string `json:"subject"`
ID string `json:"id"`
To string `json:"to"`
} `json:"public_msgs"`
}

func getMailboxDetails(localPart string) (mailboxDetails, error) {
webInboxURL := "https://www.mailinator.com/api/webinbox2?x=0&public_to=" + localPart
fmt.Println("Retrieving URL:", webInboxURL)

mbxDetails := mailboxDetails{}
resp, err := http.Get(webInboxURL)
if err != nil {
return mbxDetails, err
}

defer resp.Body.Close()
err = json.NewDecoder(resp.Body).Decode(&mbxDetails)
if err != nil {
return mbxDetails, err
}
return mbxDetails, err
}

func getCookies(mbxDetails mailboxDetails) ([]*http.Cookie, error) {
// TODO: consider allow to retrieve more than one message.
// TODO: fix panic on no messages.
// TODO: just pass in the single message; avoid duplication?
// TODO: confirm that first item is the latest message (but I think
// it is from previous testing of the bash script).
latestMsg := mbxDetails.PublicMsgs[0]

// This request is for nothing but getting required cookies.
// Otherwise, the subsequent request fails.
inboxURL := "https://www.mailinator.com/inbox2.jsp?public_to=" + latestMsg.To
fmt.Println("Retrieving URL:", inboxURL)

inboxResp, err := http.Get(inboxURL)
defer inboxResp.Body.Close()
if err != nil {
return nil, err
}

cookies := inboxResp.Cookies()
return cookies, err
}

func getMail(mbxDetails mailboxDetails, cookies []*http.Cookie) error {
// TODO: consider allow to retrieve more than one message.
// TODO: fix panic on no messages.
// TODO: just pass in the single message; avoid duplication?
// TODO: confirm that first item is the latest message (but I think
// it is from previous testing of the bash script).
latestMsg := mbxDetails.PublicMsgs[0]

msgURL := "https://www.mailinator.com/fetchmail?msgid=" + latestMsg.ID + "&zone=public"
fmt.Println("Retrieving URL:", msgURL)
req, err := http.NewRequest("GET", msgURL, nil)

for _, c := range cookies {
req.AddCookie(c)
}

client := &http.Client{}

mailResp, err := client.Do(req)
defer mailResp.Body.Close()
if err != nil {
return err
}

mailMessage := mail{}
err = json.NewDecoder(mailResp.Body).Decode(&mailMessage)
if err != nil {
return err
}

fmt.Println("\nFrom :", mailMessage.Data.From)
fmt.Println("Subject:", mailMessage.Data.Subject)
fmt.Println("\n", mailMessage.Data.Parts[0].Body)
return nil
}

func main() {
if len(os.Args) != 2 {
fmt.Println("Usage: mailin8 <local-part>")
os.Exit(1)
}

localPart := os.Args[1]
mbxDetails, err := getMailboxDetails(localPart)
if err != nil {
fmt.Println("failed to get message ID:", err)
os.Exit(1)
}

cookies, err := getCookies(mbxDetails)
if err != nil {
fmt.Println("failed to get cookies:", err)
os.Exit(1)
}

err = getMail(mbxDetails, cookies)
if err != nil {
fmt.Println("failed to get mail:", err)
os.Exit(1)
}
}

0 comments on commit bffef80

Please sign in to comment.