> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sendpost.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Supabase Edge Functions Quickstart

> Learn how to send emails with SendPost in Supabase Edge Functions using Deno runtime

## Prerequisites

To get the most out of this guide, you'll need to:

* [**Create a SendPost Account**](https://app.sendpost.io/register)
* [**Supabase Account**](https://supabase.com/) (free tier works)
* [**Supabase CLI**](https://supabase.com/docs/guides/cli) installed
* A **Sub-Account API Key** from your SendPost dashboard

<Info>
  You can find your API keys in your [SendPost Dashboard](https://app.sendpost.io). Make sure to use your Sub-Account API Key for sending emails.
</Info>

## 1. Install Supabase CLI

```bash theme={null}
npm install -g supabase
```

## 2. Initialize Supabase Project

```bash theme={null}
supabase init
supabase login
supabase link --project-ref your-project-ref
```

## 3. Create Edge Function

Create a new edge function:

```bash theme={null}
supabase functions new send-email
```

This creates a directory structure:

```
supabase/
  functions/
    send-email/
      index.ts
```

## 4. Basic Email Function

Update `supabase/functions/send-email/index.ts`:

```typescript TypeScript theme={null}
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';

const SENDPOST_API_URL = 'https://api.sendpost.io/api/v1';
const SENDPOST_API_KEY = Deno.env.get('SENDPOST_API_KEY') || '';

interface EmailRequest {
  to: string;
  subject: string;
  htmlBody: string;
  textBody?: string;
}

serve(async (req) => {
  // Handle CORS
  if (req.method === 'OPTIONS') {
    return new Response(null, {
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'POST, OPTIONS',
        'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
      },
    });
  }

  try {
    const { to, subject, htmlBody, textBody }: EmailRequest = await req.json();

    if (!to || !subject || !htmlBody) {
      return new Response(
        JSON.stringify({
          success: false,
          error: 'Missing required fields: to, subject, htmlBody',
        }),
        {
          status: 400,
          headers: {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*',
          },
        }
      );
    }

    // Prepare email message
    const emailMessage = {
      from: {
        email: 'hello@playwithsendpost.io',
        name: 'SendPost',
      },
      to: [{ email: to }],
      subject,
      htmlBody,
      textBody: textBody || htmlBody.replace(/<[^>]*>/g, ''),
      trackOpens: true,
      trackClicks: true,
    };

    // Send email via SendPost API
    const response = await fetch(`${SENDPOST_API_URL}/subaccount/email/`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-SubAccount-ApiKey': SENDPOST_API_KEY,
      },
      body: JSON.stringify(emailMessage),
    });

    if (!response.ok) {
      const error = await response.text();
      throw new Error(`SendPost API error: ${error}`);
    }

    const result = await response.json();

    return new Response(
      JSON.stringify({
        success: true,
        messageId: result.messageId,
      }),
      {
        status: 200,
        headers: {
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
        },
      }
    );
  } catch (error) {
    console.error('SendPost error:', error);
    return new Response(
      JSON.stringify({
        success: false,
        error: error.message,
      }),
      {
        status: 500,
        headers: {
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
        },
      }
    );
  }
});
```

## 5. Set Environment Variables

Set the secret in Supabase:

```bash theme={null}
supabase secrets set SENDPOST_API_KEY=your_sub_account_api_key
```

Or via Supabase Dashboard:

1. Go to Project Settings → Edge Functions
2. Add secret: `SENDPOST_API_KEY`

## 6. Deploy Function

Deploy the function:

```bash theme={null}
supabase functions deploy send-email
```

## 7. Common Use Cases

### Welcome Email Function

Create `supabase/functions/welcome-email/index.ts`:

```typescript TypeScript theme={null}
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';

const SENDPOST_API_URL = 'https://api.sendpost.io/api/v1';
const SENDPOST_API_KEY = Deno.env.get('SENDPOST_API_KEY') || '';

serve(async (req) => {
  if (req.method === 'OPTIONS') {
    return new Response(null, {
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'POST, OPTIONS',
        'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
      },
    });
  }

  try {
    const { email, firstName } = await req.json();

    if (!email || !firstName) {
      return new Response(
        JSON.stringify({
          success: false,
          error: 'Missing required fields: email, firstName',
        }),
        { status: 400, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }
      );
    }

    const emailMessage = {
      from: {
        email: 'hello@playwithsendpost.io',
        name: 'SendPost',
      },
      to: [
        {
          email,
          name: firstName,
          customFields: { firstName },
        },
      ],
      subject: 'Welcome {{firstName}}!',
      htmlBody: `
        <h1>Welcome, {{firstName}}!</h1>
        <p>Thank you for joining us. We're excited to have you on board.</p>
        <p>Get started by exploring our features:</p>
        <ul>
          <li>Feature 1</li>
          <li>Feature 2</li>
          <li>Feature 3</li>
        </ul>
        <p>If you have any questions, just reply to this email.</p>
        <p><a href="{{unsubscribe}}">Unsubscribe</a></p>
      `,
      textBody: `
        Welcome, {{firstName}}!
        
        Thank you for joining us. We're excited to have you on board.
        
        Get started by exploring our features:
        - Feature 1
        - Feature 2
        - Feature 3
        
        If you have any questions, just reply to this email.
        
        Unsubscribe: {{unsubscribe}}
      `,
      groups: ['welcome'],
      trackOpens: true,
      trackClicks: true,
    };

    const response = await fetch(`${SENDPOST_API_URL}/subaccount/email/`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-SubAccount-ApiKey': SENDPOST_API_KEY,
      },
      body: JSON.stringify(emailMessage),
    });

    const result = await response.json();

    return new Response(
      JSON.stringify({
        success: true,
        messageId: result.messageId,
      }),
      {
        status: 200,
        headers: {
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
        },
      }
    );
  } catch (error) {
    return new Response(
      JSON.stringify({
        success: false,
        error: error.message,
      }),
      {
        status: 500,
        headers: {
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
        },
      }
    );
  }
});
```

### Password Reset Email

Create `supabase/functions/password-reset/index.ts`:

```typescript TypeScript theme={null}
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';

const SENDPOST_API_URL = 'https://api.sendpost.io/api/v1';
const SENDPOST_API_KEY = Deno.env.get('SENDPOST_API_KEY') || '';

serve(async (req) => {
  if (req.method === 'OPTIONS') {
    return new Response(null, {
      headers: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'POST, OPTIONS',
        'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
      },
    });
  }

  try {
    const { email, resetToken, firstName } = await req.json();
    const appUrl = Deno.env.get('APP_URL') || 'https://yourapp.com';
    const resetUrl = `${appUrl}/reset-password?token=${resetToken}`;

    const emailMessage = {
      from: {
        email: 'hello@playwithsendpost.io',
        name: 'SendPost',
      },
      to: [
        {
          email,
          name: firstName || 'User',
          customFields: {
            firstName: firstName || 'User',
            resetUrl,
          },
        },
      ],
      subject: 'Reset Your Password',
      htmlBody: `
        <h2>Hello {{firstName}},</h2>
        <p>We received a request to reset your password. Click the button below:</p>
        <p>
          <a href="{{resetUrl}}" style="background-color: #5750EC; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">
            Reset Password
          </a>
        </p>
        <p>Or copy and paste this link: {{resetUrl}}</p>
        <p>This link will expire in 1 hour.</p>
        <p>If you didn't request this, please ignore this email.</p>
      `,
      groups: ['password-reset'],
      trackClicks: true,
    };

    const response = await fetch(`${SENDPOST_API_URL}/subaccount/email/`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-SubAccount-ApiKey': SENDPOST_API_KEY,
      },
      body: JSON.stringify(emailMessage),
    });

    const result = await response.json();

    return new Response(
      JSON.stringify({
        success: true,
        messageId: result.messageId,
      }),
      {
        status: 200,
        headers: {
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
        },
      }
    );
  } catch (error) {
    return new Response(
      JSON.stringify({
        success: false,
        error: error.message,
      }),
      {
        status: 500,
        headers: {
          'Content-Type': 'application/json',
          'Access-Control-Allow-Origin': '*',
        },
      }
    );
  }
});
```

## 8. Invoke Function

### From Client

```typescript TypeScript theme={null}
const { data, error } = await supabase.functions.invoke('send-email', {
  body: {
    to: 'user@example.com',
    subject: 'Hello from Supabase!',
    htmlBody: '<h1>Hello!</h1><p>This email was sent from Supabase Edge Functions.</p>',
  },
});
```

### Via HTTP

```bash theme={null}
curl -X POST \
  'https://your-project-ref.supabase.co/functions/v1/send-email' \
  -H 'Authorization: Bearer YOUR_ANON_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "to": "user@example.com",
    "subject": "Test Email",
    "htmlBody": "<h1>Hello!</h1>"
  }'
```

## 9. Testing Locally

Run locally:

```bash theme={null}
supabase functions serve send-email
```

Test:

```bash theme={null}
curl -X POST http://localhost:54321/functions/v1/send-email \
  -H 'Authorization: Bearer YOUR_ANON_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "to": "user@example.com",
    "subject": "Test",
    "htmlBody": "<h1>Test</h1>"
  }'
```

<Warning>
  Make sure your sender email domain is verified in your SendPost account before sending emails.
</Warning>

## 10. Next Steps

Explore more examples and use cases:

<Columns cols={3}>
  <Card title="Supabase Edge Functions" icon="supabase" href="https://supabase.com/docs/guides/functions">
    Learn more about Supabase Edge Functions
  </Card>

  <Card title="Deno Documentation" icon="deno" href="https://deno.land/docs">
    Learn more about Deno runtime
  </Card>

  <Card title="Quickstart Example" icon="github" href="https://github.com/sendpost/sendpost-supabase-edge-functions-example">
    View a complete working example on GitHub
  </Card>
</Columns>
