Language SDK

net/smtp is frozen. gomail is abandoned.

The Go team won't add features to net/smtp. gomail is unmaintained. Gmail rejects the default EHLO. MIME multipart is a nightmare. Ark sends email over HTTP—one struct, one function call, done.

26
MCP tools
Sub-second
Delivery
99.9%
Inbox rate
$0.50
Per 1K emails

Go's email story is stuck in the past

net/smtp is frozen (no new features accepted). It has no DKIM, no attachments, no timeouts by default. Gmail rejects smtp.SendMail() because it sends "localhost" as the EHLO hostname. gomail was the answer, but it's abandoned. You end up piecing together mime/multipart, hunting for the right fork, and debugging TLS handshakes.

  • ×net/smtp is frozen—Go team won't add DKIM, attachments, or timeouts
  • ×Gmail rejects default EHLO hostname ("localhost")—requires manual smtp.Client workaround
  • ×gomail is abandoned—must find the "right" fork (go-mail/mail) or face unmaintained code
  • ×MIME multipart/mixed + multipart/alternative for HTML+text+attachments is brutal

HTTP API instead of SMTP

Ark sends email over HTTPS. No SMTP ports, no TLS version debugging, no EHLO hostnames, no MIME structure. One struct, one function call, proper Go error handling.

No net/smtp—single HTTP request, no SMTP handshake
No MIME complexity—pass HTML, text, and attachments as fields
Context support—cancel requests, set timeouts with context.Context
Goroutine-safe—share one client across all goroutines
2 minutes

Replace net/smtp in 2 minutes

go get, set one environment variable, send. No smtp.Dial, no PlainAuth, no mime/multipart.

1

Install the module

Add to your Go module. Works with Go 1.21+.

go get github.com/ArkHQ-io/ark-go
2

Set your API key

One environment variable. No SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS.

export ARK_API_KEY=ark_live_xxxxxx
3

Send email

One struct, one function call. Returns message ID, returns error on failure (no silent drops).

package main

import (
    "context"
    "log"
    "os"

    "github.com/ArkHQ-io/ark-go"
)

func main() {
    client := ark.NewClient(ark.WithAPIKey(os.Getenv("ARK_API_KEY")))

    // One struct, one call. Compare to net/smtp boilerplate.
    resp, err := client.Emails.Send(context.Background(), ark.EmailSendParams{
        From:    "[email protected]",
        To:      []string{"[email protected]"},
        Subject: "Welcome!",
        HTML:    ark.String("<h1>You're in.</h1>"),
        Text:    ark.String("You're in."),  // Optional plaintext
    })
    if err != nil {
        log.Fatal(err)  // Real error, not silent failure
    }

    log.Printf("Sent: %s", resp.Data.ID)
}

Code examples

Copy and paste to get started quickly.

HTTP handler (Chi, Gin, net/http—all work)
package main

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

    "github.com/ArkHQ-io/ark-go"
)

// Goroutine-safe: share one client across all handlers
var arkClient = ark.NewClient(ark.WithAPIKey(os.Getenv("ARK_API_KEY")))

func signupHandler(w http.ResponseWriter, r *http.Request) {
    var req struct {
        Email string `json:"email"`
        Name  string `json:"name"`
    }
    json.NewDecoder(r.Body).Decode(&req)

    // Context from request = automatic timeout/cancellation
    _, err := arkClient.Emails.Send(r.Context(), ark.EmailSendParams{
        From:    "[email protected]",
        To:      []string{req.Email},
        Subject: "Welcome, " + req.Name + "!",
        HTML:    ark.String("<h1>You're in!</h1>"),
    })
    if err != nil {
        // Real error handling—not silent SMTP failure
        http.Error(w, "email failed", http.StatusInternalServerError)
        return
    }

    json.NewEncoder(w).Encode(map[string]bool{"sent": true})
}
Concurrent bulk sends (goroutines)
package main

import (
    "context"
    "log"
    "sync"

    "github.com/ArkHQ-io/ark-go"
)

// Send to thousands of users concurrently
// Compare to: one SMTP connection, serial sends, 2-5s per email
func sendBulkEmails(client *ark.Client, users []User) error {
    var wg sync.WaitGroup
    errCh := make(chan error, len(users))

    // Ark is goroutine-safe—fire hundreds of concurrent requests
    for _, user := range users {
        wg.Add(1)
        go func(u User) {
            defer wg.Done()

            ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
            defer cancel()

            _, err := client.Emails.Send(ctx, ark.EmailSendParams{
                From:    "[email protected]",
                To:      []string{u.Email},
                Subject: "Your weekly digest",
                HTML:    ark.String(renderDigest(u)),
            })
            if err != nil {
                errCh <- fmt.Errorf("%s: %w", u.Email, err)
            }
        }(user)
    }

    wg.Wait()
    close(errCh)

    // Collect any errors
    for err := range errCh {
        log.Printf("Failed: %v", err)
    }
    return nil
}
With attachments (no MIME pain)
package main

import (
    "context"
    "encoding/base64"
    "os"

    "github.com/ArkHQ-io/ark-go"
)

func sendWithAttachment(client *ark.Client, to, pdfPath string) error {
    // Read file
    data, err := os.ReadFile(pdfPath)
    if err != nil {
        return err
    }

    // Send with attachment—no mime/multipart, no content-type headers
    _, err = client.Emails.Send(context.Background(), ark.EmailSendParams{
        From:    "[email protected]",
        To:      []string{to},
        Subject: "Your invoice is ready",
        HTML:    ark.String("<p>Invoice attached.</p>"),
        Attachments: []ark.Attachment{
            {
                Filename: "invoice.pdf",
                Content:  base64.StdEncoding.EncodeToString(data),
                Type:     "application/pdf",
            },
        },
    })
    return err
}

What you can build

Escape net/smtp boilerplate

No more smtp.Dial, smtp.Client, PlainAuth, Hello(), Mail(), Rcpt(), Data(), Close(). One struct, one function call.

Concurrent bulk sends

Fire hundreds of goroutines at once. Each HTTP request is independent—no shared SMTP connection bottleneck.

Attachments without MIME pain

Pass attachments as a slice. No mime/multipart.Writer, no Content-Type headers, no boundary strings.

Microservices and CLI tools

Lightweight HTTP client initializes instantly. Works in API servers, background workers, and command-line tools.

Why developers choose Ark

No SMTP configuration

One API key replaces SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, TLS version, and EHLO hostname.

context.Context support

Pass context for timeouts and cancellation. net/smtp has no timeout support by default (hardcoded 10s).

Goroutine-safe client

Share one client across all goroutines. No connection pooling to manage, no mutex needed.

Proper Go error handling

Returns error on failure. No silent SMTP drops, no unchecked response codes.

What you get with Ark

Automatic SPF, DKIM, DMARC
Real-time webhooks
Suppression management
Unlimited domains
Unlimited team members
$2.50 (5,000 emails) welcome credit
No monthly fees

Frequently asked questions

Why not just use net/smtp?

net/smtp is frozen—the Go team won't add DKIM, attachments, or configurable timeouts. Gmail rejects the default EHLO hostname. You end up writing 50+ lines of boilerplate for basic email. Ark is 5 lines.

What about gomail?

The original go-gomail/gomail is abandoned. There's an actively maintained fork (go-mail/mail), but you're still dealing with SMTP configuration, TLS debugging, and the same Gmail EHLO issues. HTTP APIs don't have these problems.

How do I send HTML + plaintext + attachments?

With net/smtp, you need mime/multipart with nested multipart/mixed and multipart/alternative structures. With Ark, pass HTML, Text, and Attachments as fields in one struct.

Is it safe for concurrent use?

Yes. The Ark client is goroutine-safe. Create one client and share it across all goroutines. Each Send() is an independent HTTP request.

Does it support context cancellation?

Yes. All methods accept context.Context. Cancel the context and the request aborts. Set a deadline and it times out. net/smtp has no context support.

What does it cost?

$0.50 per 1,000 emails. No monthly fees. $2.50 welcome credit (5,000 emails). Most Go apps run for months on the free credit.

go get github.com/ArkHQ-io/ark-go

No net/smtp. No gomail. No MIME multipart. 2 minutes to first email.