initial commit

This commit is contained in:
2026-01-19 02:20:50 -07:00
commit d3491b8a4a
11 changed files with 397 additions and 0 deletions

9
.dockerignore Normal file
View File

@@ -0,0 +1,9 @@
__pycache__
*.pyc
venv
.venv
.env
.DS_Store
dist
build
\.pytest_cache

3
.env Normal file
View File

@@ -0,0 +1,3 @@
email="contact.dheerajgajula@gmail.com"
apppassword="astkbadcyjwbwkrq"
receipt_email="dheerajgajula.cse@gmail.com"

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
venv/
__pycache__/

20
Dockerfile Normal file
View File

@@ -0,0 +1,20 @@
FROM python:3.11-slim
# Set a working directory
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Environment variables (provided as requested)
ENV email=contact.dheerajgajula@gmail.com
ENV apppassword=astkbadcyjwbwkrq
ENV receipt_email=dheerajgajula.cse@gmail.com
# Expose port 9999 and run the FastAPI app with uvicorn
EXPOSE 9999
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "9999"]

71
README.md Normal file
View File

@@ -0,0 +1,71 @@
# Email Sender Service
This repository contains a simple `EmailSender` class and a small FastAPI service that exposes an endpoint to send emails from the configured sender to the configured recipient.
Required environment variables (e.g. in a `.env` file):
- `email` - sender email address (example: your Gmail address)
- `apppassword` - SMTP app password (for Gmail, generate an app password)
- `receipt_email` - recipient email address (where messages will be sent)
Optional environment variables for test script:
- `TEST_SUBJECT` - subject used by `test.py` if provided
- `TEST_CONTENT` - content used by `test.py` if provided
Install dependencies
It's recommended to use a virtual environment. Then:
```bash
pip install -r requirements.txt
```
Run the FastAPI service locally with uvicorn:
```bash
uvicorn main:app --reload --host 0.0.0.0 --port 8000
```
Request example (curl):
```bash
curl -X POST "http://localhost:8000/send" -H "Content-Type: application/json" -d '{"subject":"Hello","content":"This is a test"}'
```
Notes
- The service uses Gmail's SMTP by default (the existing `EmailSender` implementation). If you want to use a different SMTP provider, update `_send_email` in `email_sender.py`.
- For local development without sending real email, consider running a debug SMTP server or modifying `_send_email` to print the message when a `DRY_RUN` env var is set.
Docker
------
A simple Dockerfile is provided to containerize the service. It embeds the three environment values you requested directly into the image (`email`, `apppassword`, `receipt_email`). Embedding secrets in a Dockerfile is not generally recommended for production — see the security note below.
Build the image:
```bash
docker build -t email-service:latest .
```
Run the container (maps container port 9999 to host port 9999):
```bash
docker run -p 9999:9999 --rm email-service:latest
```
Then POST to the `/send` endpoint:
```bash
curl -X POST "http://localhost:9999/send" -H "Content-Type: application/json" -d '{"subject":"Hello","content":"This is a test"}'
```
Security note
-------------
Storing secrets (email and app passwords) in a Dockerfile is insecure because the resulting image and layers can be inspected and shared. Safer alternatives:
- Use an external environment file (`--env-file .env`) or pass `-e` flags to `docker run` to inject secrets at runtime (do not commit `.env` to source control).
- Use Docker secrets or a secret manager when deploying to orchestration platforms.

75
_mon_tech_stack.txt Normal file
View File

@@ -0,0 +1,75 @@
endpoints:
- name: resume
group: core
url: "https://resume.dheerajg.me"
interval: 10s
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 150"
- name: git
group: core
url: "https://git.dheerajg.me"
interval: 10s
conditions:
- "[STATUS] == 200"
- "[BODY].status == UP"
- "[RESPONSE_TIME] < 150"
- name: docs
group: core
url: "https://docs.dheerajg.me"
interval: 10s
conditions:
- "[STATUS] == 200"
- "[BODY].status == UP"
- "[RESPONSE_TIME] < 150"
- name: photos backup
group: core
url: "https://pic.dheerajg.me"
interval: 10s
conditions:
- "[STATUS] == 200"
- "[BODY].status == UP"
- "[RESPONSE_TIME] < 150"
- name: boulder-server-ping
group: server-stats
url: "icmp://10.0.0.10"
interval: 1m
conditions:
- "[CONNECTED] == true"
- name: intel-nuc
group: server-stats
url: "icmp://10.0.0.20"
interval: 1m
conditions:
- "[CONNECTED] == true"
- name: proxmox
group: server-stats
url: "icmp://10.0.0.30"
interval: 1m
conditions:
- "[CONNECTED] == true"
- name: check-domain-expiration
url: "https://dheerajg.me"
interval: 1h
conditions:
- "[DOMAIN_EXPIRATION] > 720h"
- name: example-dns-query
url: "8.8.8.8" # Address of the DNS server to use
interval: 10s
dns:
query-name: "example.com"
query-type: "A"
conditions:
- "[BODY] == pat(*.*.*.*)" # Matches any IPv4 address
- "[DNS_RCODE] == NOERROR"

66
email_sender.py Normal file
View File

@@ -0,0 +1,66 @@
import smtplib
from email.mime.text import MIMEText
from dotenv import load_dotenv
import os
load_dotenv()
class EmailSender:
def __init__(self):
self.email_id = os.getenv("email")
self.apppassword = os.getenv("apppassword")
self.receipt_email_id = os.getenv("receipt_email")
def message_prep(self, subject:str, email: str, body:str):
msg = MIMEText(body)
msg["Subject"] = subject
msg["From"] = self.email_id
msg['To'] = email
return msg
pass
def _send_email(self, msg:MIMEText, recipient:str):
with smtplib.SMTP_SSL("smtp.gmail.com", 465) as smtp_server:
# use the configured sender id and app password
smtp_server.login(self.email_id, self.apppassword)
smtp_server.sendmail(self.email_id, recipient, msg.as_string())
pass
def send_email(self, reason:str, email:str, body:str):
if reason == "Job Opportunity":
subject = "Your time has comeee !!!! get up !!!!"
elif reason == "Collaboration":
subject = "Time to build somthing !! getup !"
elif reason == "General":
subject = "Someone is saying hii !!"
else:
subject = "hmmm !! what could it be :)"
# send email to self
reciept_email = self.message_prep(subject=subject, email=self.receipt_email_id, body=body + f"\n \n {email} has contacted you ")
self._send_email(msg=reciept_email, recipient=self.receipt_email_id)
# send email to the contact person
contact_person_email = self.message_prep(subject=os.getenv("contact_subject"), email=email, body=os.getenv("contact_body"))
self._send_email(msg=contact_person_email, recipient=email)
pass
def send_general_email(self, subject:str, email:str, body:str):
# send email to self
reciept_email = self.message_prep(subject=subject, email=self.receipt_email_id, body=body + f"\n \n {email} has contacted you ")
self._send_email(msg=reciept_email, recipient=self.receipt_email_id)
# send email to the contact person
contact_person_email = self.message_prep(subject=os.getenv("contact_subject"), email=email, body=os.getenv("contact_body"))
self._send_email(msg=contact_person_email, recipient=email)
pass
def send_to_recipient(self, subject: str, content: str):
"""Send a simple email with given subject and content from self.email_id to self.receipt_email_id."""
if not self.email_id or not self.apppassword or not self.receipt_email_id:
raise ValueError("Missing email configuration (email, apppassword, or receipt_email).")
msg = self.message_prep(subject=subject, email=self.receipt_email_id, body=content)
self._send_email(msg=msg, recipient=self.receipt_email_id)
return True

42
main.py Normal file
View File

@@ -0,0 +1,42 @@
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import os
from email_sender import EmailSender
app = FastAPI(title="Email Sender Service")
class SendRequest(BaseModel):
subject: str
content: str
# create a single EmailSender instance for the app
es = EmailSender()
@app.get("/health")
def health():
return {"status": "ok"}
@app.post("/send")
def send_email(req: SendRequest):
"""Send an email from configured sender to configured recipient.
Expects JSON: {"subject": "...", "content": "..."}
"""
# basic config validation
missing = []
if not es.email_id:
missing.append("email")
if not es.apppassword:
missing.append("apppassword")
if not es.receipt_email_id:
missing.append("receipt_email")
if missing:
raise HTTPException(status_code=500, detail={"error": "missing_config", "missing": missing})
try:
es.send_to_recipient(subject=req.subject, content=req.content)
return {"status": "sent", "to": es.receipt_email_id}
except Exception as e:
# return the error message but avoid leaking sensitive info
raise HTTPException(status_code=500, detail={"error": "send_failed", "message": str(e)})

76
monitoring_stack.txt Normal file
View File

@@ -0,0 +1,76 @@
endpoints:
- name: resume
group: core
url: "https://resume.dheerajg.me"
interval: 10s
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 150"
- name: git
group: core
url: "https://git.dheerajg.me"
interval: 10s
conditions:
- "[STATUS] == 200"
- "[BODY].status == UP"
- "[RESPONSE_TIME] < 150"
- name: docs
group: core
url: "https://docs.dheerajg.me"
interval: 10s
conditions:
- "[STATUS] == 200"
- "[BODY].status == UP"
- "[RESPONSE_TIME] < 150"
- name: photos backup
group: core
url: "https://pic.dheerajg.me"
interval: 10s
conditions:
- "[STATUS] == 200"
- "[BODY].status == UP"
- "[RESPONSE_TIME] < 150"
- name: boulder-server-ping
group: server-stats
url: "icmp://10.0.0.10"
interval: 1m
conditions:
- "[CONNECTED] == true"
- name: intel-nuc
group: server-stats
url: "icmp://10.0.0.20"
interval: 1m
conditions:
- "[CONNECTED] == true"
- name: proxmox
group: server-stats
url: "icmp://10.0.0.30"
interval: 1m
conditions:
- "[CONNECTED] == true"
- name: check-domain-expiration
url: "https://dheerajg.me"
interval: 1h
conditions:
- "[DOMAIN_EXPIRATION] > 720h"
- name: example-dns-query
url: "8.8.8.8" # Address of the DNS server to use
interval: 10s
dns:
query-name: "example.com"
query-type: "A"
conditions:
- "[BODY] == pat(*.*.*.*)" # Matches any IPv4 address
- "[DNS_RCODE] == NOERROR"

3
requirements.txt Normal file
View File

@@ -0,0 +1,3 @@
python-dotenv==1.1.1
fastapi==0.100.0
uvicorn[standard]==0.22.0

30
test.py Normal file
View File

@@ -0,0 +1,30 @@
from email_sender import EmailSender
import os
def main():
"""Simple test runner that sends an email using EmailSender.send_to_recipient.
Make sure the following environment variables are set (for example in a .env file):
- email (sender email)
- apppassword (smtp/app password)
- receipt_email (recipient email)
Run this file and let me know whether you receive the email.
"""
subject = os.getenv('TEST_SUBJECT', 'Test email from EmailSender')
content = os.getenv('TEST_CONTENT', 'This is a test email sent by EmailSender.send_to_recipient')
es = EmailSender()
try:
print(f"Sending -> from: {es.email_id} to: {es.receipt_email_id} subject: {subject}")
es.send_to_recipient(subject=subject, content=content)
print("Send attempted — if SMTP credentials are correct, the recipient should receive the message.")
except Exception as e:
print("Error while sending email:", repr(e))
if __name__ == '__main__':
main()