---
title: "Quickstart"
description: "A key and a first send."
url: "https://openemail.uk/docs/api/quickstart"
area: "API"
category: "Getting started"
---

# Quickstart

A key and a first send.

## 1. Create a key

1. Open Settings → API keys. The page is only there if you own the mailbox.
2. Name it after whatever will use it. That name is how you find it again when something has to be revoked.
3. Choose its scopes. Sending only, by default.
4. Optionally narrow what it may send as: whole domains, single addresses, or both. A whole domain covers addresses added to it later.
5. Copy the key. It is shown once and is not recoverable: what is stored is a one-way hash. Rotating the key later shows the replacement once in the same way.

## 2. Send something

**Install**

_npm_

```bash
npm install @openemail/sdk
```

_pnpm_

```bash
pnpm add @openemail/sdk
```

_yarn_

```bash
yarn add @openemail/sdk
```

_bun_

```bash
bun add @openemail/sdk
```

> Optional. Every endpoint is plain HTTP and JSON, and the curl tab below needs nothing installed at all.

**Send your first email**

_curl_

```bash
curl -X POST https://api.openemail.uk/emails \
  -H "Authorization: Bearer $OPENEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme Billing <billing@acme.com>",
    "to": ["ada@example.com"],
    "subject": "Your September invoice",
    "html": "<p>Invoice attached.</p>"
  }'
```

_TypeScript_

```typescript
import { init, openemail } from '@openemail/sdk'

init({ apiKey: process.env.OPENEMAIL_API_KEY })

const email = await openemail.emails.send({
  from: 'Acme Billing <billing@acme.com>',
  to: 'ada@example.com',
  subject: 'Your September invoice',
  html: '<p>Invoice attached.</p>',
})

console.log(email.id, email.status)
```

_Python_

```python
import os, requests

res = requests.post(
    "https://api.openemail.uk/emails",
    headers={"Authorization": f"Bearer {os.environ['OPENEMAIL_API_KEY']}"},
    json={
        "from": "Acme Billing <billing@acme.com>",
        "to": ["ada@example.com"],
        "subject": "Your September invoice",
        "html": "<p>Invoice attached.</p>",
    },
    timeout=30,
)
res.raise_for_status()
print(res.json()["id"], res.json()["status"])
```

_PHP_

```php
<?php
$res = json_decode(file_get_contents("https://api.openemail.uk/emails", false, stream_context_create([
    "http" => [
        "method"  => "POST",
        "header"  => "Authorization: Bearer " . getenv("OPENEMAIL_API_KEY") . "\r\n" .
                     "Content-Type: application/json",
        "content" => json_encode([
            "from"    => "Acme Billing <billing@acme.com>",
            "to"      => ["ada@example.com"],
            "subject" => "Your September invoice",
            "html"    => "<p>Invoice attached.</p>",
        ]),
    ],
])), true);

echo $res["id"], " ", $res["status"];
```

_Ruby_

```ruby
require "net/http"
require "json"

res = Net::HTTP.post(
  URI("https://api.openemail.uk/emails"),
  {
    from: "Acme Billing <billing@acme.com>",
    to: ["ada@example.com"],
    subject: "Your September invoice",
    html: "<p>Invoice attached.</p>"
  }.to_json,
  "Authorization" => "Bearer #{ENV.fetch('OPENEMAIL_API_KEY')}",
  "Content-Type" => "application/json"
)

puts JSON.parse(res.body).values_at("id", "status").join(" ")
```

_Go_

```go
body, _ := json.Marshal(map[string]any{
    "from":    "Acme Billing <billing@acme.com>",
    "to":      []string{"ada@example.com"},
    "subject": "Your September invoice",
    "html":    "<p>Invoice attached.</p>",
})

req, _ := http.NewRequest("POST", "https://api.openemail.uk/emails", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("OPENEMAIL_API_KEY"))
req.Header.Set("Content-Type", "application/json")

res, err := http.DefaultClient.Do(req)
```

_Java_

```java
var body = """
    {
      "from": "Acme Billing <billing@acme.com>",
      "to": ["ada@example.com"],
      "subject": "Your September invoice",
      "html": "<p>Invoice attached.</p>"
    }""";

var request = HttpRequest.newBuilder(URI.create("https://api.openemail.uk/emails"))
    .header("Authorization", "Bearer " + System.getenv("OPENEMAIL_API_KEY"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

var res = HttpClient.newHttpClient().send(request, BodyHandlers.ofString());
System.out.println(res.body());
```

_C#_

```csharp
using var http = new HttpClient();
http.DefaultRequestHeaders.Add(
    "Authorization",
    $"Bearer {Environment.GetEnvironmentVariable("OPENEMAIL_API_KEY")}");

var res = await http.PostAsJsonAsync("https://api.openemail.uk/emails", new
{
    from = "Acme Billing <billing@acme.com>",
    to = new[] { "ada@example.com" },
    subject = "Your September invoice",
    html = "<p>Invoice attached.</p>",
});

Console.WriteLine(await res.Content.ReadAsStringAsync());
```

A `200` means it has gone. You get back an `id`. Keep it: it is how you retrieve the message, read its event trail, or cancel it if you scheduled it.

> Getting a 403 you did not expect? `GET /addresses` lists exactly what this key may send as. It is almost always the send scope on the key, a domain or an address it was not given, rather than a missing domain on the workspace.
