textbee Logotextbee.dev
Plans from $9.99/mo.View Plans

Forward SMS to email automatically from your own Android number

Published and updated

Install textbee on the Android phone that holds the SIM, register a webhook for received messages, and run a short relay that turns each webhook into an email over SMTP. The subject carries the sender number and the body carries the text, so replies to the phone number stay searchable in your inbox.

What you need

  • The textbee app on the Android phone that holds the SIM, with receiving turned on. Download the app.
  • A place to run the relay with a public HTTPS address: a small server, a container or a serverless function. textbee rejects private and loopback addresses.

Before you start

  1. Pick the mailbox that sends the forwards. For Gmail, turn on 2-Step Verification on that Google account and create an app password; SMTP login with the normal password is refused.
  2. Note the SMTP server and port: smtp.gmail.com on port 587 with STARTTLS for Gmail, or the values your mail provider publishes.
  3. Decide the address that receives the forwards. It can be the same mailbox or a shared inbox.

The relay

It checks the HMAC-SHA256 signature in the X-Signature header, skips anything but received messages, and ignores a delivery it has already forwarded. When the destination is down it answers 502, so textbee delivers the text again later; an error a retry cannot fix, such as a deleted webhook, is logged instead. It needs Python 3 and only the standard library, so there is nothing to install.

relay.py
import hashlib
import hmac
import json
import os
import smtplib
import ssl
from email.message import EmailMessage
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

SECRET = os.environ["TEXTBEE_WEBHOOK_SECRET"].encode()
SMTP_HOST = os.environ.get("SMTP_HOST", "smtp.gmail.com")
SMTP_PORT = int(os.environ.get("SMTP_PORT", 587))
SMTP_STARTTLS = os.environ.get("SMTP_STARTTLS", "true").lower() not in ("false", "0", "no")
SMTP_USER = os.environ["SMTP_USER"]
SMTP_PASSWORD = os.environ["SMTP_PASSWORD"]
MAIL_TO = os.environ["MAIL_TO"]
MAX_BODY = 64 * 1024
seen = set()  # use your database in production


def forward(event):
    mail = EmailMessage()
    mail["Subject"] = f"SMS from {event['sender']}"
    mail["From"] = SMTP_USER
    mail["To"] = MAIL_TO
    mail.set_content(f"{event['message']}\n\nReceived {event['receivedAt']}")
    with smtplib.SMTP(SMTP_HOST, SMTP_PORT, timeout=20) as smtp:
        if SMTP_STARTTLS:
            smtp.starttls(context=ssl.create_default_context())
        smtp.login(SMTP_USER, SMTP_PASSWORD)
        smtp.send_message(mail)


class Relay(BaseHTTPRequestHandler):
    timeout = 15  # drop a connection that stalls mid-request

    def do_POST(self):
        length = int(self.headers.get("Content-Length", 0))
        if length > MAX_BODY:
            return self.answer(413)
        raw_body = self.rfile.read(length)
        expected = hmac.new(SECRET, raw_body, hashlib.sha256).hexdigest()
        if not hmac.compare_digest(expected, self.headers.get("X-Signature", "")):
            return self.answer(401)

        event = json.loads(raw_body)
        if event["webhookEvent"] != "MESSAGE_RECEIVED" or event["idempotencyKey"] in seen:
            return self.answer(200)

        try:
            forward(event)
            seen.add(event["idempotencyKey"])
            self.answer(200)
        except Exception as error:
            print(error, flush=True)
            self.answer(502)  # a 5xx answer makes textbee retry the delivery

    def answer(self, status):
        self.send_response(status)
        self.end_headers()


ThreadingHTTPServer(("", int(os.environ.get("PORT", 3000))), Relay).serve_forever()
Environment variableWhat it holds
TEXTBEE_WEBHOOK_SECRETThe signing secret you set on the webhook in the textbee dashboard, at least 20 characters.
SMTP_HOSTSMTP server. Defaults to smtp.gmail.com.
SMTP_PORTSMTP port. Defaults to 587.
SMTP_STARTTLSSet to false only for a local relay without TLS. Defaults to true.
SMTP_USERMailbox that sends the forwards, also used as the From address.
SMTP_PASSWORDApp password for that mailbox, not the account password.
MAIL_TOAddress that receives the forwarded texts.
PORTPort the relay listens on. Defaults to 3000.

Register the webhook in textbee

  1. Start the relay and note its public HTTPS address.
  2. In the textbee dashboard open Webhooks, choose Create Webhook, and enter that address as the Delivery URL.
  3. Generate a Signing Secret, select the MESSAGE_RECEIVED event, and set the same secret as TEXTBEE_WEBHOOK_SECRET on the relay.
  4. Text the phone from a different phone and check that the forward arrives.

What arrives

Webhook fieldWhere it goes
senderSubject: "SMS from +12015550123"
messageEmail body
receivedAtLast line of the body

Limits to plan for

  • A personal Gmail account that sends more than 500 emails in a day is blocked from sending for 1 to 24 hours. support.google.com, checked on September 23, 2026
  • A Google Workspace user can send 2,000 messages a day, or 500 on a trial account. knowledge.workspace.google.com, checked on September 23, 2026
  • App passwords work only on accounts with 2-Step Verification turned on, and are not available for work or school accounts or Advanced Protection. support.google.com, checked on September 23, 2026

Mail providers cap how many messages a mailbox sends a day, and a burst of forwards from a new mailbox can land in spam. Send from a mailbox you control, forward to an address that trusts it, and keep the subject plain.

textbee delivers the webhook once the phone has uploaded the text, so a phone that was offline delivers its backlog when it reconnects. Texts received more than 48 hours before the upload are stored but not sent to webhooks. A 5xx answer or a timeout is retried, up to 10 attempts in all with growing gaps, and a subscription that keeps failing is paused. Received messages count toward the plan allowance the same as sent ones.

Frequently asked questions

Can I forward SMS to email without a server?

The relay has to run somewhere with a public HTTPS address, because textbee delivers webhooks over the internet and rejects private and loopback addresses. A small VPS, a container platform or a serverless function all work. The phone itself does not forward anything.

Does forwarding SMS to email work with Gmail?

Yes. Gmail accepts SMTP logins with an app password once 2-Step Verification is on for the account. Use smtp.gmail.com, port 587 and STARTTLS, which are the relay defaults.

Can I reply to the email to answer the text?

Not with this relay. Replies need a second step that reads the mailbox and calls POST /gateway/send-sms. Most teams reply from the textbee dashboard or from their own app instead.

Do forwarded messages count toward my textbee plan?

Received messages count toward the plan allowance the same as sent ones. Forwarding to email adds no textbee messages, because the email goes out over SMTP.

Sources

  1. support.google.com, checked on September 23, 2026
  2. knowledge.workspace.google.com, checked on September 23, 2026
  3. support.google.com, checked on September 23, 2026

Read next