Giter Club home page Giter Club logo

mailgun-go's Issues

Clarify (and rename?) API keys required

The current mailgun-go requires two keys to be specified:

  • API Key
  • Public API Key

Mailgun has recently (?) changed the names of these keys, so the "Public API Key" is now called "Email Validation Key". Also, they call the "API Key" "Active API Key".

Maybe the docs should be updated to reflect this?

And it would be good if it was enough to specify only the "API Key" if validation is not used in the mailgun-go API.

Stats

  • GET //stats
  • DELETE //tags/

.GetStoredMessage fails with wrong URL message

// from a webhook handler
url := r.PostFormValue("message-url")
urlp := strings.Split(url, "/")
err := mailgun.Client.GetStoredMessage(urlp[len(urlp)-1])

Generates an error that reads as

UnexpectedResponseError
URL=https://api.mailgun.net/v2/domains/mydomain.com/messages/eyJwIjpmYWxzZSaWFwiayZDgxNzc0LWJaWFlMzItNGYS1hM2E2LTc4NzUwYWRhZjMaWF3OCIsInMiOiJkYzRjZmIiwiYyI6InNhaWFkIn0=
ExpectedOneOf=[]int{200, 202, 204}
Got=400
Error: {"message":"Please use URLs as they are given in events/webhooks"}

While the value of url was https://si.api.mailgun.net/v3/domains/mydomain.com/messages/eyJwIjpmYWxzZSaWFwiayZDgxNzc0LWJaWFlMzItNGYS1hM2E2LTc4NzUwYWRhZjMaWF3OCIsInMiOiJkYzRjZmIiwiYyI6InNhaWFkIn0=.

Email validation occasionally causing whole application to crash

The way mailgun/mailgun-go interacts with the mbanzon/simplehttp library can sometimes result in a whole application crash (SEGFAULT) when validating email, stacktrace follows.

The way I am calling the mg.ValidateEmail function is as follows: emailvalid, _ := mg.ValidateEmail(email) // (email is a sanitised string)

This issue is paired with another issue created on the mbanzon/simplehttp repository - https://github.com/mbanzon/simplehttp/issues/8

Stacktrace:

unexpected fault address 0x7f7500000011
fatal error: fault
[signal 0xb code=0x1 addr=0x7f7500000011]

 goroutine 16 [running]:
    :0
...
:0
 goroutine 1 [IO wait]:
 main.main
    /root/gocode/src/mlc/controller.go:293 // This is just a simple log.Fatal(http.ListenAndServe("127.0.0.1:2369", m))

 goroutine 4 [chan receive]:

 goroutine 10 [select]:
 github.com_mbanzon_simplehttp.MakeRequest.pN41_github.com_mbanzon_simplehttp.HTTPRequest
    /root/gocode/src/github.com/mbanzon/simplehttp/simplehttp.go:108
 github.com_mbanzon_simplehttp.MakeGetRequest.pN41_github.com_mbanzon_simplehttp.HTTPRequest
    /root/gocode/src/github.com/mbanzon/simplehttp/simplehttp.go:59
 mailgun.getResponseFromJSON
    /root/gocode/src/github.com/mailgun/mailgun-go/rest_shim.go:72
 github.com_mailgun_mailgun_go.ValidateEmail.pN41_github.com_mailgun_mailgun_go.MailgunImpl
    /root/gocode/src/github.com/mailgun/mailgun-go/email_validation.go:49
 main.$nested0
    /root/gocode/src/mlc/controller.go:138
 github.com_codegangsta_inject.Invoke.pN38_github.com_codegangsta_inject.injector
    /root/gocode/src/github.com/codegangsta/inject/inject.go:102
 github.com_go_martini_martini.Invoke.N37_github.com_go_martini_martini.context
    /root/gocode/src/github.com/go-martini/martini/martini.go:144
 github.com_go_martini_martini.Invoke.N42_github.com_go_martini_martini.routeContext
    /root/gocode/src/github.com/go-martini/martini/router.go:336
 github.com_go_martini_martini.run.pN42_github.com_go_martini_martini.routeContext
    /root/gocode/src/github.com/go-martini/martini/router.go:350
 github.com_go_martini_martini.Handle.pN35_github.com_go_martini_martini.route
    /root/gocode/src/github.com/go-martini/martini/router.go:229
 github.com_go_martini_martini.Handle.pN36_github.com_go_martini_martini.router
    /root/gocode/src/github.com/go-martini/martini/router.go:112
 github.com_codegangsta_inject.Invoke.pN38_github.com_codegangsta_inject.injector
    /root/gocode/src/github.com/codegangsta/inject/inject.go:102
 github.com_go_martini_martini.Invoke.N37_github.com_go_martini_martini.context
    /root/gocode/src/github.com/go-martini/martini/martini.go:144
 github.com_go_martini_martini.run.pN37_github.com_go_martini_martini.context
    /root/gocode/src/github.com/go-martini/martini/martini.go:173
 github.com_go_martini_martini.Next.pN37_github.com_go_martini_martini.context
    /root/gocode/src/github.com/go-martini/martini/martini.go:164
 martini.$nested2
    /root/gocode/src/github.com/go-martini/martini/recovery.go:140
 github.com_codegangsta_inject.Invoke.pN38_github.com_codegangsta_inject.injector
    /root/gocode/src/github.com/codegangsta/inject/inject.go:102
 github.com_go_martini_martini.Invoke.N37_github.com_go_martini_martini.context
    /root/gocode/src/github.com/go-martini/martini/martini.go:144
 github.com_go_martini_martini.run.pN37_github.com_go_martini_martini.context
    /root/gocode/src/github.com/go-martini/martini/martini.go:173
 github.com_go_martini_martini.Next.pN37_github.com_go_martini_martini.context
    /root/gocode/src/github.com/go-martini/martini/martini.go:164
 martini.$nested0
    /root/gocode/src/github.com/go-martini/martini/logger.go:25
 github.com_codegangsta_inject.Invoke.pN38_github.com_codegangsta_inject.injector
    /root/gocode/src/github.com/codegangsta/inject/inject.go:102
 github.com_go_martini_martini.Invoke.N37_github.com_go_martini_martini.context
    /root/gocode/src/github.com/go-martini/martini/martini.go:144
 github.com_go_martini_martini.run.pN37_github.com_go_martini_martini.context
    /root/gocode/src/github.com/go-martini/martini/martini.go:173
 github.com_go_martini_martini.ServeHTTP.pN37_github.com_go_martini_martini.Martini
    /root/gocode/src/github.com/go-martini/martini/martini.go:69
 github.com_go_martini_martini.ServeHTTP.N44_github.com_go_martini_martini.ClassicMartini
    /root/gocode/src/github.com/go-martini/martini/martini.go:105

Configure SMTP Server

Hi,

I'm a bit fuzzy on this, but I'm assuming the domain is the SMTP server. I basically have MailHog running, and I want all my e-mails to go to MailHog during development, but I can't find where to set the SMTP server that I hit.

I'm wondering if it's the domain we set when we create the mailgun.

Thanks.

Webhooks Timeout

The functions to create and update webhooks time out frequently.

Unable to send mails with only HTML content

Is there a specific reason why all attributes of a message are private and there are no accessor methods? Would be really helpful to be able to read these values. I'll submit a pull request if its welcome. Wanted to know the thinking behind this decision before doing it though.

Also, it seems that a text version of the message is required. Every time I try to send a message with just an HTML body I get "Message not valid". Another conscious decision? The Mailgun API doesn't suggest that this is required and to my knowledge it shouldn't be.

Add support for Polling Events

Implement event polling as described in the mailgun docs here

mg := mailgun.NewMailgunFromEnv()
it := mg.PollEvents(EventOptions{ThresholdAge: time.Minute, TimeRange: time.Hour})
var events []Event
// Blocks until new events appear
for it.Poll(&events) {
	for _, event := range(events) {
		fmt.Printf("Event %+v\n", event)
	}
}

How does the text and HTML version work?

Exploring the Go API examples. I see that the message content is added two times in second example, first time as text (when using .newMessage()) and second time as HTML (using .setHTML()). How does this work?
Which of these contents will be sent in the email? or both? or is it something else?

members.json request is not right

func (mg *MailgunImpl) CreateMemberList(s *bool, addr string, newMembers []interface{}) error {
    r := simplehttp.NewHTTPRequest(generateMemberApiUrl(listsEndpoint, addr) + ".json")
    r.SetBasicAuth(basicAuthUser, mg.ApiKey())
    p := simplehttp.NewFormDataPayload()
    if s != nil {
        p.AddValue("subscribed", yesNo(*s))
    }
    bs, err := json.Marshal(newMembers)
    if err != nil {
        return err
    }
    fmt.Println(string(bs))
    p.AddValue("members", string(bs))
    _, err = makePostRequest(r, p)
    return err
}

in the api document, no subscribed form value, you should change to same the api docuemnt. change subscribed to upsert。

p.AddValue("subscribed", yesNo(*s))
=>
p.AddValue("upsert", yesNo(s))

package "testing" imported in non-testing code

In acceptance.go, package "testing" is imported, and so is imported by anything using the mailgun go package. (In particular, that showed up to me as the testing command line flags showing up in a main package that was using the mailgun package.)

Perhaps acceptance.go should instead be acceptance_test.go? It seems the functions within are only used by other *_test.go files.

Complaints

  • GET //complaints
  • GET //complaints/
  • POST //complaints
  • DELETE //complaints/

Bounce Code Type Issue

In the Bounce struct of bounces.go, the Mailgun API returns a Code of type Int or String.

To duplicate, issue gun.GetBounces(-1, -1). If any bounces in the first page of 100 results contain a string and int in the Bounce, you'll get a type error when the json library unmarshalls the Code result to the Bounce struct.

"Error: json: cannot unmarshal string into Go value of type int"

Mailing Lists

  • GET /lists
  • GET /lists/
  • POST /lists
  • PUT /lists/
  • DELETE /lists/
  • GET /lists//members
  • GET /lists//members/<member_address>
  • POST /lists//members
  • PUT /lists//members/<member_address>
  • POST /lists//members.json
  • DELETE /lists//members/<member_address>

NewMailgun - publicApiKey

I suppose the function

func NewMailgun(domain, apiKey, publicApiKey string) Mailgun {
    m := MailgunImpl{domain: domain, apiKey: apiKey, publicApiKey: publicApiKey}
    return &m
}

has a publicApiKey because the API v2 uses it? I cannot find any reference to it at the documentation / website of Mailgun, and leaving it blank enables me to send the e-mail anyway.

What's its use? And why is it still there?

Bounces

  • GET //bounces
  • GET //bounces/
  • POST //bounces
  • DELETE //bounces/

API v3

Is the upgrade to API v3 planned? Or is this project abandoned?

I'm not sure if there are any changes, but the URL changed, so there should be a reason for that? (at least we should update the URL mailgun-go uses.

too many open files error?

Already adjusted to

ulimit -n
65536

but still get lots of error:

Get https://api.mailgun.net/v2/address/parse?addresses=foo%40bar.com: dial tcp: lookup api.mailgun.net on 10.0.0.2:53: dial udp 10.0.0.2:53: too many open files

my codes:

func send(subject, body string, to ...string) error {
    mg := mailgun.NewMailgun(mailgunDomain, mailgunPrivateKey, mailgunPublicKey)
    addrs, err := parseAddrs(mg, to...)
    if err != nil {
        return err
    }

    m := mg.NewMessage(
        mailgunFrom, // From
        subject,     // Subject
        body,        // Plain-text body
        addrs...,    // Recipients (vararg list)
    )

    _, _, err = mg.Send(m)
    return err
}

func parseAddrs(mg mailgun.Mailgun, to ...string) ([]string, error) {
    addrs, unparseable, err := mg.ParseAddresses(to...)
    if err != nil {
        return nil, err
    }

    for _, invalid := range unparseable {
        fmt.Println(invalid)
        // todo send slack alert
    }

    return addrs, nil
}

Unsubscribes

  • GET //unsubscribes
  • GET //unsubscribes/
  • DELETE //unsubscribes/
  • POST //unsubscribes

Is there any way to introspect messages?

I'm trying to mock out mailgun so that all messages get captured and can later be introspected for correct application behavior.

Here's a snippet of the mock:

type MockMailGun struct {
    SentMessages chan *mailgun.Message

    // Embed the Mailgun interface. No idea what will happen if unimplemented methods are called.
    mailgun.Mailgun
}

func (mmg *MockMailGun) Send(m *mailgun.Message) (string, string, error) {
    defer func() {
        mmg.SentMessages <- m
    }()
    return "", "", nil
}

But I'm running into a problem when I try to look at the messages to introspect previous calls that were made to Message.AddHeader(), because there's no way to get the headers (or any other metadata about the message.

Here's what I'd like to be able to do:

func (mmg *MockMailGun) waitForNotification(nt NotificationType) {

    message := <-mmg.SentMessages
    if message.GetHeader("MyHeader") == "foo" {
        // Can't do this, no way to get header from message
    }

}

But there is no message.GetHeader() available in the API.

Is there any recommended way of doing this kind of mock or being able to introspect messages?

Hopefully this is the right place to ask this, I didn't see a link to a forum or group .. but let me know if I should post this somewhere else.

Campaigns

  • GET //campaigns
  • GET //campaigns/
  • POST //campaigns
  • PUT //campaigns/
  • DELETE //campaigns/
  • GET //campaigns//events
  • GET //campaigns//stats
  • GET //campaigns//clicks
  • GET //campaigns//opens
  • GET //campaigns//unsubscribes
  • GET //campaigns//complaints

Routes

  • GET /routes
  • GET /routes/
  • POST /routes
  • PUT /routes/
  • DELETE /routes/

Discussion: How to best report errors for the mailgun api?

@mbanzon ,

I've run into situations where a request against mailgun API would fail, but errors are not propegated back to the caller of the API, at least through the err return. I've confirmed that simplehttp is not, seemingly by design, addressing 4xx or 5xx responses as errors.

Should we be inserting an abstraction layer between mailgun-go and simplehttp that does return code validation? I'm of the opinion that this is a good idea, as it'd simplify the interface from the caller's perspective. Thoughts?

Webhooks

  • GET /domains//webhooks
  • GET /domains//webhooks/
  • POST /domains//webhooks
  • PUT /domains//webhooks/
  • DELETE /domains//webhooks/

Messages

  • POST //messages
  • POST //messages.mime
  • GET domains//messages
  • DELETE domains//messages/

Compilation error on "acceptance"

The acceptance package can't be compiled without the proper build tag.

Some files are missing the build tag but requiring the function reqEnv (included in a file that has the build tag) making a standard build of the package fail.

GetStoredMessage fails with "Please use URLs as they are given in events/webhooks"

When passing in the storage.key of an event to the GetStoredMessage function, I get something like:

UnexpectedResponseError
URL=https://api.mailgun.net/v3/domains/example.com/messages/STORAGEKEY
ExpectedOneOf=[]int{200, 202, 204} Got=400
Error: {"message":"Please use URLs as they are given in events/webhooks"}

The URL provided by the event's storage.url uses a slightly different domain:

https://so.api.mailgun.net/v3/domains/example.com/messages/STORAGEKEY

Which, if followed (with proper credentials) gives the proper response.

The only difference from the URL generated by GetStoredMessage is the "so." sub-sub-domain, for what that is worth.

Add travis or any other CI for tests

Hi,

do you plan to implement a CI test environment like travis, wercker, ...?
It's free and it's easier to check the contributed PRs.
You could, for example, check for test coverage, formatting and many more.

If you want, I will contribute travis or wecker integration.

Thanks and

best regards

Domains

  • GET /domains
  • GET /domains/
  • POST /domains
  • DELETE /domains/
  • GET /domains//credentials
  • POST /domains//credentials
  • PUT /domains//credentials/
  • DELETE /domains//credentials/

Remove simplehttp dependency

This heavily relates to #24.

IMHO dependencies to external libraries should be removed if possible. The only reason that mailgun-go use simplehttp is that I originally wrote both libraries in parallel.

Hiding simplehttp and its implementation bring trouble when it is needed to use alternative http.Client or http.Transport (when writing application for GAE eg.).

use golang style iterators

Currently iterating through events looks like this.

	ei := mg.NewEventIterator()
	err := ei.GetFirstPage(GetEventsOptions{})
	for {
		if err != nil {
			return "", err
		}
		if len(ei.Events()) == 0 {
			break
		}
		for _, event := range ei.Events() {
			// Do things with **events**
		}
		err = ei.GetNext()
	}

I wish to change this to a more golang idiomatic

	it := mg.ListEvents(EventsOptions{})
	var events []Event
	for it.Next(&events) {
		for _, event := range events {
                        // Do things with **events**
		}
	}
        if it.Err() != nil {
               return "", it.Err()
        }

I bring this up because I'm currently implementing support for GET /v3/{domain}/tags which also would use an iterator as eventually we expect customers to have lots of tags. I would love to see a consistent iterator interface for the user.

Events pagination

I'm implementing a dashboard for mailgun (https://github.com/Xotelia/mailgun-dashboard). I have a question regarding the event pagination. There is a next and previous link in event API response. But with the implementation of the API I have to request the first page and then, if we are on page ten I will have to call GetNext() 10 times. Is it possible to pass an offset to GetEventsOptions? And also, how the pagination works ? based on timestamp? Offset? whatever?

GetUnsubscribes returns unsubscribes even after RemoveUnsubscribe called

I have a background process that periodically polls for unsubscribe events. I noticed in the log that it appears to be processing the same addresses each time it runs, even though I'm calling RemoveUnsubscribe with the unsubscribe events' IDs.

Perhaps I'm doing something incorrectly, or I've misunderstood these calls.

Any help is appreciated.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.