Upload files to "mailling"
This is python scripts for storing mail body to mongoDB and script to send mail body from mongoDB
This commit is contained in:
parent
3d8400a5af
commit
6bbb9f5944
19
mailling/config.json
Normal file
19
mailling/config.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"SMPT": {
|
||||
"SMPTSERVER": "smtp.gmail.com",
|
||||
"PORT": 587,
|
||||
"SENDER_EMAIL": "marcoioitsoft@gmail.com",
|
||||
"SENDER_PASSWORD": "qrtq wfuj hwpp fhqr"
|
||||
},
|
||||
"API": {
|
||||
"BASE_URL": "http://localhost:5032/api",
|
||||
"USERNAME": "admin@marcoaiot.com",
|
||||
"PASSWORD": "User@123"
|
||||
},
|
||||
"MONGODB":{
|
||||
"MONGO_CONNECTION_STRING": "mongodb://localhost:27017",
|
||||
"DATABASE_NAME": "MarcoBMS_Caches",
|
||||
"COLLECTION_NAME": "ProjectReportMail"
|
||||
}
|
||||
}
|
||||
|
319
mailling/send_project_report_email.py
Normal file
319
mailling/send_project_report_email.py
Normal file
@ -0,0 +1,319 @@
|
||||
import smtplib
|
||||
import requests
|
||||
import ssl
|
||||
import json
|
||||
from email.message import EmailMessage
|
||||
import pymongo
|
||||
from pymongo.errors import ConnectionFailure, OperationFailure, PyMongoError
|
||||
from bson.objectid import ObjectId # Import ObjectId for querying by _id
|
||||
|
||||
# --- Configuration Loading ---
|
||||
def load_config_from_json(file_path="config.json"):
|
||||
"""Loads configuration from a JSON file."""
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
config = json.load(f)
|
||||
print(f"Configuration loaded from {file_path}")
|
||||
return config
|
||||
except FileNotFoundError:
|
||||
print(f"Error: Configuration file '{file_path}' not found. Please create it.")
|
||||
exit(1)
|
||||
except json.JSONDecodeError:
|
||||
print(f"Error: Could not decode JSON from '{file_path}'. Check file format for errors.")
|
||||
exit(1)
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred while loading config: {e}")
|
||||
exit(1)
|
||||
|
||||
# Load configuration at the start
|
||||
CONFIG = load_config_from_json()
|
||||
|
||||
# Access variables from the nested configuration
|
||||
SMPT_CONFIG = CONFIG.get("SMPT", {})
|
||||
SMTP_SERVER = SMPT_CONFIG.get("SMPTSERVER")
|
||||
SMTP_PORT = int(SMPT_CONFIG.get("PORT")) if SMPT_CONFIG.get("PORT") is not None else None
|
||||
SENDER_EMAIL = SMPT_CONFIG.get("SENDER_EMAIL")
|
||||
SENDER_PASSWORD = SMPT_CONFIG.get("SENDER_PASSWORD")
|
||||
|
||||
API_CONFIG = CONFIG.get("API", {})
|
||||
BASE_URL = API_CONFIG.get("BASE_URL")
|
||||
API_USERNAME = API_CONFIG.get("USERNAME")
|
||||
API_PASSWORD = API_CONFIG.get("PASSWORD")
|
||||
|
||||
MONGODB_CONFIG = CONFIG.get("MONGODB", {})
|
||||
MONGO_CONNECTION_STRING = MONGODB_CONFIG.get("MONGO_CONNECTION_STRING")
|
||||
DATABASE_NAME = MONGODB_CONFIG.get("DATABASE_NAME")
|
||||
COLLECTION_NAME = MONGODB_CONFIG.get("COLLECTION_NAME")
|
||||
|
||||
# Validate essential configuration (more robust check)
|
||||
if not (SMTP_SERVER and SMTP_PORT and SENDER_EMAIL and SENDER_PASSWORD and
|
||||
BASE_URL and API_USERNAME and API_PASSWORD and
|
||||
MONGO_CONNECTION_STRING and DATABASE_NAME and COLLECTION_NAME):
|
||||
print("Error: One or more essential configuration variables are missing or invalid in config.json.")
|
||||
# Print which specific parts are missing for easier debugging
|
||||
missing_configs = []
|
||||
if not SMTP_SERVER: missing_configs.append("SMPT.SMPTSERVER")
|
||||
if not SMTP_PORT: missing_configs.append("SMPT.PORT")
|
||||
if not SENDER_EMAIL: missing_configs.append("SMPT.SENDER_EMAIL")
|
||||
if not SENDER_PASSWORD: missing_configs.append("SMPT.SENDER_PASSWORD")
|
||||
if not BASE_URL: missing_configs.append("API.BASE_URL")
|
||||
if not API_USERNAME: missing_configs.append("API.USERNAME")
|
||||
if not API_PASSWORD: missing_configs.append("API.PASSWORD")
|
||||
if not MONGO_CONNECTION_STRING: missing_configs.append("MONGODB.MONGO_CONNECTION_STRING")
|
||||
if not DATABASE_NAME: missing_configs.append("MONGODB.DATABASE_NAME")
|
||||
if not COLLECTION_NAME: missing_configs.append("MONGODB.COLLECTION_NAME")
|
||||
print(f"Missing/Invalid: {', '.join(missing_configs)}")
|
||||
exit(1)
|
||||
|
||||
# Create a default SSL context once for secure connections
|
||||
SSL_CONTEXT = ssl.create_default_context()
|
||||
|
||||
# --- API Functions ---
|
||||
def login_api():
|
||||
"""Logs into the API and returns the JWT token."""
|
||||
payload = {"username": API_USERNAME, "password": API_PASSWORD}
|
||||
headers = {"Content-Type": "application/json"}
|
||||
try:
|
||||
response = requests.post(f"{BASE_URL}/auth/login", json=payload, headers=headers, timeout=10) # Add timeout
|
||||
response.raise_for_status()
|
||||
data = response.json().get("data") # Use .get() for safer access
|
||||
jwt = data.get("token") if data else None # Safely get token
|
||||
if jwt:
|
||||
print("API login successful.")
|
||||
return jwt
|
||||
else:
|
||||
print("API response missing 'data' or 'token' key.")
|
||||
return None
|
||||
except requests.exceptions.HTTPError as e:
|
||||
print(f"HTTP Error during API login: {e} - Response: {getattr(e.response, 'text', 'N/A')}")
|
||||
return None
|
||||
except requests.exceptions.Timeout:
|
||||
print("Timeout Error during API login: The server did not respond in time.")
|
||||
return None
|
||||
except requests.exceptions.ConnectionError:
|
||||
print("Connection Error during API login: Could not connect to the API server. Check URL and network.")
|
||||
return None
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"An unexpected error occurred during API login: {e}")
|
||||
return None
|
||||
except json.JSONDecodeError:
|
||||
print(f"API response is not valid JSON for login: {response.text}")
|
||||
return None
|
||||
|
||||
def get_email_bodies_from_api(jwt):
|
||||
"""Retrieves email body data from the API."""
|
||||
if not jwt:
|
||||
print("No JWT token available to get email bodies.")
|
||||
return []
|
||||
|
||||
headers = {"Authorization": f"Bearer {jwt}", "Content-Type": "application/json"}
|
||||
try:
|
||||
response = requests.get(f"{BASE_URL}/report/report-mail", headers=headers, timeout=10) # Add timeout
|
||||
response.raise_for_status()
|
||||
data = response.json().get("data") # Safely get data
|
||||
if isinstance(data, list):
|
||||
print(f"Successfully retrieved {len(data)} email bodies from API.")
|
||||
return data
|
||||
else:
|
||||
print("API response for report-mail is missing 'data' key or it's not a list.")
|
||||
return []
|
||||
except requests.exceptions.HTTPError as e:
|
||||
print(f"HTTP Error when getting email bodies: {e} - Response: {getattr(e.response, 'text', 'N/A')}")
|
||||
return []
|
||||
except requests.exceptions.Timeout:
|
||||
print("Timeout Error when getting email bodies: The server did not respond in time.")
|
||||
return []
|
||||
except requests.exceptions.ConnectionError:
|
||||
print("Connection Error when getting email bodies: Could not connect to the API server. Check URL and network.")
|
||||
return []
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"An error occurred when getting email bodies: {e}")
|
||||
return []
|
||||
except json.JSONDecodeError:
|
||||
print(f"API response for getting email bodies is not valid JSON: {response.text}")
|
||||
return []
|
||||
|
||||
# --- SMTP Functions ---
|
||||
def login_smtp():
|
||||
"""Logs into the SMTP server and returns the server object."""
|
||||
server = None
|
||||
try:
|
||||
server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
|
||||
server.starttls(context=SSL_CONTEXT)
|
||||
print("TLS connection established.")
|
||||
|
||||
server.login(SENDER_EMAIL, SENDER_PASSWORD)
|
||||
print("Logged in to SMTP server successfully.")
|
||||
return server
|
||||
except smtplib.SMTPAuthenticationError as e:
|
||||
print(f"SMTP Authentication Error: {e}")
|
||||
print("Please check your email address and password/app password.")
|
||||
print("For Gmail, ensure 'Less secure app access' is OFF and you're using an App Password.")
|
||||
print("For Outlook, you might need to generate an App Password.")
|
||||
if server: server.quit()
|
||||
return None
|
||||
except smtplib.SMTPServerDisconnected as e:
|
||||
print(f"SMTP Server Disconnected Error: {e}")
|
||||
print("The SMTP server unexpectedly disconnected. Check network or server status.")
|
||||
if server: server.quit()
|
||||
return None
|
||||
except smtplib.SMTPException as e:
|
||||
print(f"SMTP Error: {e}")
|
||||
print("An error occurred during the SMTP transaction.")
|
||||
if server: server.quit()
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred during SMTP login: {e}")
|
||||
if server: server.quit()
|
||||
return None
|
||||
|
||||
def send_email(smtp_server, receiver_email, subject, body):
|
||||
"""Sends an HTML email using a pre-logged-in SMTP server."""
|
||||
if not smtp_server:
|
||||
print("SMTP server not initialized. Cannot send email.")
|
||||
return False
|
||||
|
||||
msg = EmailMessage()
|
||||
msg["From"] = SENDER_EMAIL
|
||||
msg["Subject"] = subject
|
||||
|
||||
msg.add_alternative(body, subtype="html")
|
||||
|
||||
if isinstance(receiver_email, str):
|
||||
receiver_email = [receiver_email]
|
||||
|
||||
msg["To"] = ", ".join(receiver_email)
|
||||
recipients_for_log = ", ".join(receiver_email)
|
||||
|
||||
print(f"Attempting to send email from {SENDER_EMAIL} to {recipients_for_log}...")
|
||||
|
||||
try:
|
||||
smtp_server.send_message(msg, from_addr=SENDER_EMAIL, to_addrs=receiver_email)
|
||||
print(f"Email sent successfully to {recipients_for_log}!")
|
||||
return True
|
||||
except smtplib.SMTPRecipientsRefused as e:
|
||||
print(f"Recipient Refused Error: {e.recipients}")
|
||||
print(f"Email not sent to some recipients: {recipients_for_log}. Check recipient addresses.")
|
||||
return False
|
||||
except smtplib.SMTPException as e:
|
||||
print(f"SMTP Error during sending: {e}")
|
||||
print(f"Could not send email to {recipients_for_log}.")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred while sending email: {e}")
|
||||
print(f"Could not send email to {recipients_for_log}.")
|
||||
return False
|
||||
|
||||
# --- MongoDB Functions ---
|
||||
def update_mongodb_document(query, new_values, upsert=False, multi=False):
|
||||
"""
|
||||
Connects to MongoDB and updates documents in a specified collection.
|
||||
"""
|
||||
client = None # Initialize client to None for finally block
|
||||
try:
|
||||
# Establish a connection to MongoDB
|
||||
# The serverSelectionTimeoutMS helps prevent long waits if the server is unreachable
|
||||
client = pymongo.MongoClient(
|
||||
MONGO_CONNECTION_STRING, serverSelectionTimeoutMS=5000
|
||||
)
|
||||
|
||||
# The ping command is cheap and does not require auth.
|
||||
# This will raise an exception if the connection fails.
|
||||
client.admin.command("ping")
|
||||
print("MongoDB connection successful!")
|
||||
|
||||
# Access the specified database and collection
|
||||
db = client[DATABASE_NAME]
|
||||
collection = db[COLLECTION_NAME]
|
||||
|
||||
print(
|
||||
f"Attempting to update document(s) in '{DATABASE_NAME}.{COLLECTION_NAME}'..."
|
||||
)
|
||||
print(f"Query: {query}")
|
||||
print(f"New Values: {new_values}")
|
||||
|
||||
if multi:
|
||||
# Update multiple documents
|
||||
result = collection.update_many(query, new_values, upsert=upsert)
|
||||
print(
|
||||
f"Matched {result.matched_count} document(s) and modified {result.modified_count} document(s)."
|
||||
)
|
||||
if result.upserted_id:
|
||||
print(f"Upserted a new document with _id: {result.upserted_id}")
|
||||
else:
|
||||
# Update a single document
|
||||
result = collection.update_one(query, new_values, upsert=upsert)
|
||||
print(
|
||||
f"Matched {result.matched_count} document(s) and modified {result.modified_count} document(s)."
|
||||
)
|
||||
if result.upserted_id:
|
||||
print(f"Upserted a new document with _id: {result.upserted_id}")
|
||||
|
||||
return result
|
||||
|
||||
except ConnectionFailure as e:
|
||||
print(
|
||||
f"MongoDB Connection Error: Could not connect to server. Please check connection string and server status. Error: {e}"
|
||||
)
|
||||
except OperationFailure as e:
|
||||
print(
|
||||
f"MongoDB Operation Error: An error occurred during a database operation. Error: {e}"
|
||||
)
|
||||
except PyMongoError as e:
|
||||
print(f"PyMongo Error: An unexpected PyMongo error occurred: {e}")
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred: {e}")
|
||||
finally:
|
||||
# Ensure the client connection is closed
|
||||
if client:
|
||||
client.close()
|
||||
print("MongoDB connection closed.")
|
||||
return None
|
||||
|
||||
|
||||
# --- Main execution logic ---
|
||||
if __name__ == "__main__":
|
||||
jwt_token = login_api()
|
||||
|
||||
if jwt_token:
|
||||
# Call add_email_body_to_api only if necessary, e.g., if you're populating the DB
|
||||
# For a regular report sending script, you might only need to get_email_bodies_from_api
|
||||
email_objects = get_email_bodies_from_api(jwt_token)
|
||||
|
||||
if email_objects:
|
||||
smtp_connection = login_smtp()
|
||||
if smtp_connection:
|
||||
for item in email_objects:
|
||||
receivers = item.get("receivers")
|
||||
subject = item.get("subject")
|
||||
body = item.get("body")
|
||||
|
||||
if receivers and subject and body:
|
||||
send_success = send_email(
|
||||
smtp_connection, receivers, subject, body
|
||||
)
|
||||
if send_success:
|
||||
try:
|
||||
# Ensure you have an actual _id from your database for this to work
|
||||
document_id_string = item.get("id")
|
||||
query_by_id = {"_id": ObjectId(document_id_string)}
|
||||
update_by_id_values = {"$set": {"IsSent": True}}
|
||||
update_mongodb_document(
|
||||
query_by_id, update_by_id_values
|
||||
)
|
||||
except Exception as e:
|
||||
print(
|
||||
f"Error in Example 5: Make sure the _id string is valid and exists. {e}"
|
||||
)
|
||||
else:
|
||||
print(
|
||||
f"Skipping email due to missing data in API response: {item}"
|
||||
)
|
||||
smtp_connection.quit() # Ensure SMTP connection is closed after all emails are sent
|
||||
print("SMTP connection closed.")
|
||||
else:
|
||||
print("Failed to establish SMTP connection. Cannot send emails.")
|
||||
else:
|
||||
print("No email bodies retrieved from API to send.")
|
||||
else:
|
||||
print("Failed to obtain JWT token. Cannot proceed with email operations.")
|
106
mailling/store_project_report_email.py
Normal file
106
mailling/store_project_report_email.py
Normal file
@ -0,0 +1,106 @@
|
||||
import json
|
||||
import requests
|
||||
|
||||
# --- Configuration ---
|
||||
def load_config_from_json(file_path="config.json"):
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
config = json.load(f)
|
||||
print(f"Configuration loaded from {file_path}")
|
||||
return config
|
||||
except FileNotFoundError:
|
||||
print(f"Error: Configuration file '{file_path}' not found.")
|
||||
exit(1)
|
||||
except json.JSONDecodeError:
|
||||
print(f"Error: Could not decode JSON from '{file_path}'. Check file format.")
|
||||
exit(1)
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred while loading config: {e}")
|
||||
exit(1)
|
||||
|
||||
# Load configuration at the start
|
||||
CONFIG = load_config_from_json()
|
||||
# Access variables from the nested configuration
|
||||
# Accessing API section
|
||||
API_CONFIG = CONFIG.get('API', {}) # Use .get() with a default empty dict to prevent KeyError if 'API' is missing
|
||||
BASE_URL = API_CONFIG.get('BASE_URL')
|
||||
API_USERNAME = API_CONFIG.get('USERNAME')
|
||||
API_PASSWORD = API_CONFIG.get('PASSWORD')
|
||||
|
||||
def login_api():
|
||||
"""
|
||||
Logs into the API and returns the JWT token.
|
||||
Handles potential request errors.
|
||||
"""
|
||||
payload = {
|
||||
"username": API_USERNAME,
|
||||
"password": API_PASSWORD
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(f"{BASE_URL}/auth/login", json=payload, headers=headers)
|
||||
response.raise_for_status() # Raise an exception for HTTP errors (4xx or 5xx)
|
||||
data = response.json()['data']
|
||||
jwt = data["token"]
|
||||
print("API login successful.")
|
||||
return jwt
|
||||
except requests.exceptions.HTTPError as e:
|
||||
print(f"HTTP Error during API login: {e}")
|
||||
print(f"Response: {response.text}")
|
||||
return None
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
print(f"Connection Error during API login: {e}")
|
||||
return None
|
||||
except requests.exceptions.Timeout as e:
|
||||
print(f"Timeout Error during API login: {e}")
|
||||
return None
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"An unexpected error occurred during API login: {e}")
|
||||
return None
|
||||
except KeyError:
|
||||
print("API response missing 'data' or 'token' key.")
|
||||
return None
|
||||
|
||||
def add_email_body_to_api(jwt):
|
||||
"""
|
||||
Adds email body data to the API.
|
||||
"""
|
||||
if not jwt:
|
||||
print("No JWT token available to add email body.")
|
||||
return None
|
||||
|
||||
headers = {
|
||||
"Authorization": f"Bearer {jwt}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
try:
|
||||
# Assuming this POST request adds new mail records to the database.
|
||||
# If it's idempotent (can be called multiple times without issues), it's fine.
|
||||
# Otherwise, consider if this should only be called once or based on specific logic.
|
||||
response = requests.post(f"{BASE_URL}/report/add-report-mail", headers=headers)
|
||||
response.raise_for_status()
|
||||
print("Email body successfully added to API.")
|
||||
return response
|
||||
except requests.exceptions.HTTPError as e:
|
||||
print(f"HTTP Error when adding email body: {e}")
|
||||
print(f"Response: {response.text}")
|
||||
return None
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"An error occurred when adding email body: {e}")
|
||||
return None
|
||||
|
||||
|
||||
# --- Main execution logic ---
|
||||
if __name__ == "__main__":
|
||||
jwt_token = login_api()
|
||||
|
||||
if jwt_token:
|
||||
# Call add_email_body_to_api only if necessary, e.g., if you're populating the DB
|
||||
# For a regular report sending script, you might only need to get_email_bodies_from_api
|
||||
add_response = add_email_body_to_api(jwt_token)
|
||||
else:
|
||||
print("Failed to obtain JWT token. Cannot proceed with email operations.")
|
Loading…
x
Reference in New Issue
Block a user