Skip to content

Commit

Permalink
Merge pull request #2 from rishabkumar7/rk-relay-sms
Browse files Browse the repository at this point in the history
added python code for send-and-receive-sms-anonymously-python
  • Loading branch information
cmsunu28 authored Sep 8, 2024
2 parents dc3f631 + d6e6bba commit f05373a
Show file tree
Hide file tree
Showing 5 changed files with 376 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
TWILIO_ACCOUNT_SID="<YOUR_TWILIO_ACCOUNT_SID>"
TWILIO_AUTH_TOKEN="<YOUR_TWILIO_AUTH_TOKEN>"
MY_PHONE_NUMBER="<YOUR_PHONE_NUMBER>"
TWILIO_PHONE_NUMBER="<YOUR_TWILIO_PHONE_NUMBER>"
164 changes: 164 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# Python .gitignore file from - https://github.com/github/gitignore/blob/main/Python.gitignore

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
85 changes: 84 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,84 @@
# send-and-receive-sms-anonymously-python
# Send and Receive SMS Anonymously Python

## Description

This Flask application serves as an SMS relay using Twilio. It allows you to use a Twilio phone number as a proxy for sending and receiving SMS messages, effectively masking your personal phone number from the public.
When the Twilio phone number associated with this application receives a message:

- If the message is from your personal number, it forwards the message to a specified recipient.
- If the message is from any other number, it relays the message to your personal number.

## Table of Contents

1. Installation
2. Configuration
3. Usage
4. License

## Installation

Clone this repository:

```sh
git clone https://github.com/twilio-samples/send-and-receive-sms-anonymously-python.git

cd twilio-sms-relay
```

Create and activate a virtual environment:

```sh
python -m venv venv
source venv/bin/activate # On Windows use `venv\Scripts\activate`
```

Install the required packages:

```sh
pip install -r requirements.txt
```

## Configuration

You will need a [Twilio Phone number](https://help.twilio.com/articles/223135247) and your Twilio Account SID and AUTH Token.
Set up the following environment variables, copy the `.env.example` and create a new `.env` file:

```
TWILIO_ACCOUNT_SID="your_account_sid"
TWILIO_AUTH_TOKEN="your_auth_token"
MY_PHONE_NUMBER="your_personal_number"
TWILIO_PHONE_NUMBER="your_twilio_number"
```

## Usage

Run the Flask application:

```sh
python app.py
```

The application will start on `http://127.0.0.1:5000/`.

Install ngrok: https://ngrok.com/download

In another terminal, start ngrok:

```sh
ngrok http 5000
```

Use the ngrok URL with `/sms` as the endpoint as your Twilio webhook URL, for example `https://xxxxxx.ngrok.app/sms`.

To send a message through the relay, text your Twilio number from your personal number with the format:

```
+1XXXXXXXXXX: Your message here
```

Replace `+1XXXXXXXXXX` with the recipient's phone number.
Any messages sent to your Twilio number will be forwarded to your personal number.

## License

This project is licensed under the MIT License - see the [LICENSE](/LICENSE) file for details.
101 changes: 101 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"""
Twilio SMS Relay Flask Application
Description: This Flask application acts as an SMS relay using Twilio.
When the associated Twilio phone number receives a message, it either
forwards the message to a specified number or relays it to your personal number.
Contents:
1. Imports and Setup
2. Environment Variables
3. Main Handler (sms_reply function)
4. Application Entry Point
"""

# 1. Imports and Setup
#
# Here we import the necessary libraries and initialize our Flask application.
# We also set up the Twilio client for making API calls.

from flask import Flask, request
from twilio.twiml.messaging_response import MessagingResponse
from twilio.rest import Client
import os

from dotenv import load_dotenv
load_dotenv()


app = Flask(__name__)


# 2. Environment Variables
#
# We load the necessary credentials and phone numbers from environment variables.
# This keeps sensitive information out of the code and allows for easier configuration
# across different environments.

TWILIO_ACCOUNT_SID = os.getenv('TWILIO_ACCOUNT_SID')
TWILIO_AUTH_TOKEN = os.getenv('TWILIO_AUTH_TOKEN')
MY_PHONE_NUMBER = os.getenv('MY_PHONE_NUMBER')
TWILIO_PHONE_NUMBER = os.getenv('TWILIO_PHONE_NUMBER')

# Initialize Twilio client
client = Client(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)

# 3. Main Handler (sms_reply function)
#
# This is the main entry point of our application. It handles incoming SMS messages
# and determines how to process them based on the sender's number.
# If the message is from your personal number, it parses the message to send to another recipient.
# If the message is from any other number, it forwards the message to your personal number.

@app.route("/sms", methods=['POST'])
def sms_reply():
# Extract incoming message details
from_number = request.form['From']
to_number = request.form['To']
body = request.form['Body']

# Initialize TwiML response
resp = MessagingResponse()

if from_number == MY_PHONE_NUMBER:
# Message is from your personal number
separator_position = body.find(':')

if separator_position < 1:
# If the message format is incorrect, send an instructional message back
resp.message('You need to specify a recipient number and a ":" before the message. For example, "+12223334444: message".')
else:
# Parse the recipient number and message body
recipient_number = body[:separator_position].strip()
message_body = body[separator_position + 1:].strip()

try:
# Attempt to send the message using Twilio client
client.messages.create(
to=recipient_number,
from_=to_number,
body=message_body
)
except Exception as e:
# If there's an error (e.g., invalid phone number), send an error message back
resp.message('There was an issue with the phone number you entered; please verify it is correct and try again.')
else:
# Message is from another number, forward it to your personal number
client.messages.create(
to=MY_PHONE_NUMBER,
from_=TWILIO_PHONE_NUMBER,
body=f"{from_number}: {body}"
)

# Return the TwiML response
return str(resp)

# 4. Application Entry Point
#
# This section runs the Flask application when the script is executed directly.
# The debug mode is set to True, which is useful for development but should be set to False in production.
if __name__ == "__main__":
app.run(debug=True)
23 changes: 23 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
aiohappyeyeballs==2.4.0
aiohttp==3.10.5
aiohttp-retry==2.8.3
aiosignal==1.3.1
attrs==24.2.0
blinker==1.8.2
certifi==2024.8.30
charset-normalizer==3.3.2
click==8.1.7
Flask==3.0.3
frozenlist==1.4.1
idna==3.8
itsdangerous==2.2.0
Jinja2==3.1.4
MarkupSafe==2.1.5
multidict==6.0.5
PyJWT==2.9.0
python-dotenv==1.0.1
requests==2.32.3
twilio==9.2.4
urllib3==2.2.2
Werkzeug==3.0.4
yarl==1.9.7

0 comments on commit f05373a

Please sign in to comment.