Merge branch 'python-email-with-charts'
This commit is contained in:
commit
3564e14e80
246
aws-s3-migration/aws-s3-migrate-documents.py
Normal file
246
aws-s3-migration/aws-s3-migrate-documents.py
Normal file
@ -0,0 +1,246 @@
|
||||
import json
|
||||
import os
|
||||
import mysql.connector
|
||||
import boto3
|
||||
import sys
|
||||
|
||||
# --- Configuration Loading ---
|
||||
|
||||
CONFIG_FILE = 'config.json'
|
||||
|
||||
def load_config():
|
||||
"""Loads configuration from config.json."""
|
||||
if not os.path.exists(CONFIG_FILE):
|
||||
print(f"Error: Configuration file '{CONFIG_FILE}' not found.")
|
||||
sys.exit(1)
|
||||
try:
|
||||
with open(CONFIG_FILE, 'r') as f:
|
||||
return json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"Error decoding JSON in config file: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# --- S3 Helper Functions ---
|
||||
|
||||
def generate_new_s3_key(old_key, prefix):
|
||||
"""
|
||||
Generates a new S3 key by prepending the destination prefix to the old key,
|
||||
thereby preserving the original path structure.
|
||||
"""
|
||||
if not isinstance(old_key, str) or not old_key:
|
||||
return None
|
||||
|
||||
# Ensure the prefix ends with a slash if it's not empty and doesn't already end with one.
|
||||
prefixed_path = prefix
|
||||
if prefix and not prefix.endswith('/'):
|
||||
prefixed_path += '/'
|
||||
|
||||
# Combine the prefix and the old key. If the old key starts with a slash, strip it.
|
||||
final_key = old_key.lstrip('/')
|
||||
|
||||
return f"{prefixed_path}{final_key}"
|
||||
|
||||
|
||||
def move_s3_object(s3_client, source_bucket, source_key, dest_bucket, dest_key):
|
||||
"""
|
||||
Performs the S3 'move' operation (Copy + Delete).
|
||||
|
||||
Returns True on success, False otherwise.
|
||||
"""
|
||||
copy_source = {
|
||||
'Bucket': source_bucket,
|
||||
'Key': source_key
|
||||
}
|
||||
|
||||
try:
|
||||
print(f" -> Copying '{source_key}' to '{dest_key}' in '{dest_bucket}'...")
|
||||
# 1. Copy the object
|
||||
s3_client.copy_object(
|
||||
CopySource=copy_source,
|
||||
Bucket=dest_bucket,
|
||||
Key=dest_key
|
||||
)
|
||||
print(" -> Copy object successful.")
|
||||
|
||||
# print(f" -> Deleting original object from '{source_bucket}/{source_key}'...")
|
||||
# # 2. Delete the original object
|
||||
# s3_client.delete_object(
|
||||
# Bucket=source_bucket,
|
||||
# Key=source_key
|
||||
# )
|
||||
# print(" -> Delete object successful.")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f" -> S3 Move FAILED for {source_key}: {e}")
|
||||
return False
|
||||
|
||||
# --- MySQL Helper Functions ---
|
||||
|
||||
def fetch_documents(db_config_full):
|
||||
"""
|
||||
Connects to MySQL and fetches all documents (ID and S3Key).
|
||||
NOTE: db_config_full includes the 'table' key, which must be filtered out for the connection.
|
||||
"""
|
||||
conn = None
|
||||
cursor = None
|
||||
|
||||
# Separate connection parameters from the table name
|
||||
table_name = db_config_full['table']
|
||||
connection_config = {k: v for k, v in db_config_full.items() if k != 'table'}
|
||||
|
||||
try:
|
||||
# Connect using only valid connection parameters
|
||||
conn = mysql.connector.connect(**connection_config)
|
||||
cursor = conn.cursor()
|
||||
|
||||
print(f"Fetching document IDs and S3Keys from table: {table_name}...")
|
||||
|
||||
# Select all ID and S3Key (or whatever column holds the key)
|
||||
query = f"SELECT ID, S3Key FROM {table_name} order by UploadedAt desc limit 10"
|
||||
cursor.execute(query)
|
||||
|
||||
# Fetch results as a list of dictionaries/tuples
|
||||
documents = cursor.fetchall()
|
||||
print(f"Found {len(documents)} documents to process.")
|
||||
return documents
|
||||
|
||||
except mysql.connector.Error as err:
|
||||
print(f"MySQL Error: {err}")
|
||||
return []
|
||||
|
||||
finally:
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if conn and conn.is_connected():
|
||||
conn.close()
|
||||
|
||||
def update_document_key(db_config_full, doc_id, new_s3_key):
|
||||
"""
|
||||
Updates the S3Key for a specific document ID in the database.
|
||||
NOTE: db_config_full includes the 'table' key, which must be filtered out for the connection.
|
||||
"""
|
||||
conn = None
|
||||
cursor = None
|
||||
|
||||
# Separate connection parameters from the table name
|
||||
table_name = db_config_full['table']
|
||||
connection_config = {k: v for k, v in db_config_full.items() if k != 'table'}
|
||||
|
||||
try:
|
||||
# Connect using only valid connection parameters
|
||||
conn = mysql.connector.connect(**connection_config)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Prepare the UPDATE query
|
||||
update_query = (
|
||||
f"UPDATE {table_name} SET S3Key = %s WHERE ID = %s"
|
||||
)
|
||||
|
||||
cursor.execute(update_query, (new_s3_key, doc_id))
|
||||
|
||||
# Commit the transaction to apply the changes
|
||||
conn.commit()
|
||||
print(f" -> DB Update SUCCESS for ID {doc_id}.")
|
||||
return True
|
||||
|
||||
except mysql.connector.Error as err:
|
||||
print(f" -> DB Update FAILED for ID {doc_id}: {err}. Rolling back.")
|
||||
if conn:
|
||||
conn.rollback()
|
||||
return False
|
||||
|
||||
finally:
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if conn and conn.is_connected():
|
||||
conn.close()
|
||||
|
||||
# --- Main Migration Logic ---
|
||||
|
||||
def main():
|
||||
"""Executes the S3 migration and database update workflow."""
|
||||
config = load_config()
|
||||
|
||||
# Initialize S3 Client
|
||||
aws_config = config['aws']
|
||||
try:
|
||||
s3_client = boto3.client(
|
||||
's3',
|
||||
aws_access_key_id=aws_config['aws_access_key_id'],
|
||||
aws_secret_access_key=aws_config['aws_secret_access_key'],
|
||||
region_name=aws_config['aws_region']
|
||||
)
|
||||
print("S3 client initialized successfully.")
|
||||
except Exception as e:
|
||||
print(f"Failed to initialize S3 client: {e}")
|
||||
return
|
||||
|
||||
# Fetch Documents
|
||||
documents = fetch_documents(config['mysql'])
|
||||
if not documents:
|
||||
print("No documents found or failed to connect to the database. Exiting.")
|
||||
return
|
||||
|
||||
source_bucket = aws_config['source_bucket']
|
||||
dest_bucket = aws_config['destination_bucket']
|
||||
key_prefix = aws_config['destination_key_prefix']
|
||||
|
||||
success_count = 0
|
||||
failure_count = 0
|
||||
|
||||
print("\n--- Starting Document Migration Process ---")
|
||||
|
||||
for doc_id, old_s3_key in documents:
|
||||
print(f"\nProcessing Document ID: {doc_id}, Old Key: {old_s3_key}")
|
||||
|
||||
if not old_s3_key:
|
||||
print(f" -> Skipping ID {doc_id}: S3Key is empty.")
|
||||
failure_count += 1
|
||||
continue
|
||||
|
||||
# 1. Generate new key, preserving path structure
|
||||
new_s3_key = generate_new_s3_key(old_s3_key, key_prefix)
|
||||
if not new_s3_key:
|
||||
print(f" -> Skipping ID {doc_id}: Could not generate new key from old key.")
|
||||
failure_count += 1
|
||||
continue
|
||||
|
||||
print(f" -> Calculated New Key: {new_s3_key}")
|
||||
|
||||
# 2. Move S3 object (Copy + Delete)
|
||||
move_successful = move_s3_object(
|
||||
s3_client,
|
||||
source_bucket,
|
||||
old_s3_key,
|
||||
dest_bucket,
|
||||
new_s3_key
|
||||
)
|
||||
|
||||
if move_successful:
|
||||
# 3. Update database
|
||||
db_update_successful = update_document_key(
|
||||
config['mysql'],
|
||||
doc_id,
|
||||
new_s3_key
|
||||
)
|
||||
|
||||
if db_update_successful:
|
||||
success_count += 1
|
||||
else:
|
||||
# If DB update fails, the S3 object is MOVED. Log critical error.
|
||||
print(f"CRITICAL: DB update failed for ID {doc_id}. Object is MOVED to {dest_bucket}/{new_s3_key}. Manual DB correction needed.")
|
||||
failure_count += 1
|
||||
else:
|
||||
# If S3 move failed, the object remains in the source bucket.
|
||||
print(f"S3 move failed for ID {doc_id}. Object remains in {source_bucket}/{old_s3_key}. DB not updated.")
|
||||
failure_count += 1
|
||||
|
||||
|
||||
print("\n--- Migration Summary ---")
|
||||
print(f"Total documents processed: {len(documents)}")
|
||||
print(f"Successful migrations (S3 Move + DB Update): {success_count}")
|
||||
print(f"Failed migrations: {failure_count}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
18
aws-s3-migration/config.json
Normal file
18
aws-s3-migration/config.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"mysql": {
|
||||
"host": "147.93.98.152",
|
||||
"user": "devuser",
|
||||
"password": "AppUser@123$",
|
||||
"database": "MarcoBMSStage",
|
||||
"table": "Documents"
|
||||
},
|
||||
"aws": {
|
||||
"aws_access_key_id": "AKIARZDBH3VDKXLBMDX6",
|
||||
"aws_secret_access_key": "ZEnwQuN9vWi+KodD+gvNEz46VCZ6/4ue3UKLbTTs",
|
||||
"aws_region": "us-east-1",
|
||||
"source_bucket": "testenv-marco-pms-documents",
|
||||
"destination_bucket": "tryenv-marco-pms-documents",
|
||||
"destination_key_prefix": "",
|
||||
"destination_key_prefix_how": "IMPORTANT: The original S3Key (e.g., 'reports/2024/doc.pdf') will be APPENDED to this prefix, preserving the path structure. Resulting Key: 'migrated_files/reports/2024/doc.pdf'"
|
||||
}
|
||||
}
|
||||
1
aws-s3-migration/readme.MD
Normal file
1
aws-s3-migration/readme.MD
Normal file
@ -0,0 +1 @@
|
||||
https://wiki.marcoaiot.com/index.php/AWS_S3_Migration_Script
|
||||
157
mailling/mail-templates/charts.html
Normal file
157
mailling/mail-templates/charts.html
Normal file
@ -0,0 +1,157 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>CSS Donut Variants</title>
|
||||
<style>
|
||||
.donut {
|
||||
--percentage: 65; /* Change this per chart */
|
||||
--primary: #e63946; /* Fill color */
|
||||
--track: #e9ecef; /* Background track */
|
||||
--size: 120px; /* Default size */
|
||||
--thickness: 20px; /* Default thickness */
|
||||
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
border-radius: 50%;
|
||||
background: conic-gradient(
|
||||
var(--primary) calc(var(--percentage) * 1%),
|
||||
var(--track) 0
|
||||
);
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.donut::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: calc(var(--size) - var(--thickness));
|
||||
height: calc(var(--size) - var(--thickness));
|
||||
border-radius: 50%;
|
||||
background: #fff; /* Inner cut-out */
|
||||
}
|
||||
|
||||
.donut span {
|
||||
position: absolute;
|
||||
font-size: calc(var(--size) / 6);
|
||||
}
|
||||
|
||||
/* Variants */
|
||||
.donut.thin {
|
||||
--size: 80px;
|
||||
--thickness: 12px;
|
||||
}
|
||||
.donut.medium {
|
||||
--size: 120px;
|
||||
--thickness: 25px;
|
||||
}
|
||||
.donut.large {
|
||||
--size: 180px;
|
||||
--thickness: 35px;
|
||||
}
|
||||
|
||||
|
||||
.progress {
|
||||
width: 100%;
|
||||
background-color: #e9ecef;
|
||||
border-radius: 0.375rem;
|
||||
overflow: hidden;
|
||||
height: 0.51rem; /* Default height */
|
||||
|
||||
margin-bottom: 1rem;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 0.375rem; /* Default size */
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.progress.thin {
|
||||
height: 0.7rem;
|
||||
font-size: 0.6rem;
|
||||
|
||||
}
|
||||
.progress.medium {
|
||||
height: 1rem;
|
||||
font-size: 0.7rem;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.progress.large {
|
||||
height: 1.5rem;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
|
||||
.progress-bar {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
|
||||
background-color: #0d6efd; /* default = Bootstrap primary */
|
||||
transition: width 0.6s ease;
|
||||
}
|
||||
|
||||
/* Color variants */
|
||||
.progress-bar-success {
|
||||
background-color: #198754;
|
||||
}
|
||||
.progress-bar-warning {
|
||||
background-color: #ffc107;
|
||||
color: #000;
|
||||
}
|
||||
.progress-bar-danger {
|
||||
background-color: #dc3545;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="display:block; gap:40px; align-items:center; justify-content:center; min-height:100vh;">
|
||||
<div style="
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
">
|
||||
<!-- Thin -->
|
||||
<div class="donut thin" style="--percentage: 45;">
|
||||
<span>45%</span>
|
||||
</div>
|
||||
|
||||
<!-- Medium -->
|
||||
<div class="donut medium" style="--percentage: 73;">
|
||||
<span>73%</span>
|
||||
</div>
|
||||
|
||||
<!-- Large -->
|
||||
<div class="donut large" style="--percentage: 90;">
|
||||
<span>90%</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div style="
|
||||
margin-top: 100px;
|
||||
">
|
||||
<div class="progress" style="width:200px">
|
||||
<div class="progress-bar" style="width: 25%;">25%</div>
|
||||
</div>
|
||||
|
||||
<div class="progress thin " style="width:200px">
|
||||
<div class="progress-bar progress-bar-success" style="width: 50%;">50%</div>
|
||||
</div>
|
||||
|
||||
<div class="progress medium" style="width:200px">
|
||||
<div class="progress-bar progress-bar-warning" style="width: 75%;">75%</div>
|
||||
</div>
|
||||
|
||||
<div class="progress large" style="width:50%">
|
||||
<div class="progress-bar progress-bar-danger" style="width: 90%;">90%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
598
mailling/mail-templates/dpr.html
Normal file
598
mailling/mail-templates/dpr.html
Normal file
@ -0,0 +1,598 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Daily Progress Report</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
background: #f5f5f5;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1100px;
|
||||
margin: 20px auto;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header {
|
||||
background: #b10000;
|
||||
color: #fff;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 22px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.header .project-info {
|
||||
font-size: 14px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.status-note {
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
padding: 15px 20px 0 20px;
|
||||
}
|
||||
|
||||
.status-cards {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 15px;
|
||||
padding: 20px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.card {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
/* <-- added shadow */
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
border-top: 1px solid #e63946;
|
||||
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
font-size: 14px;
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.card p {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.card .value {
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 0.9rem;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.attendance {
|
||||
color: #b10000;
|
||||
}
|
||||
|
||||
.tasks {
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.completion {
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
.activities {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.activities h2 {
|
||||
font-size: 18px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.table th,
|
||||
.table td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
.footer {
|
||||
background: #b10000;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: #fff;
|
||||
margin: 0 8px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 600px) {
|
||||
.header {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header .project-info {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.status-cards {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.legend {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.legend-color {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 2px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.legend-red {
|
||||
background: #b10000;
|
||||
}
|
||||
|
||||
.legend-blue {
|
||||
background: #007bff;
|
||||
}
|
||||
|
||||
.legend-green {
|
||||
background: #28a745;
|
||||
}
|
||||
|
||||
.legend-gray {
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.donut {
|
||||
--percentage: 65;
|
||||
/* Change this per chart */
|
||||
--danger: #e63946;
|
||||
--primary: #007bff;
|
||||
--warning: #ffc107;
|
||||
--success: #198754;
|
||||
/* Fill color */
|
||||
--track: #e9ecef;
|
||||
/* Background track */
|
||||
--size: 120px;
|
||||
/* Default size */
|
||||
--thickness: 20px;
|
||||
/* Default thickness */
|
||||
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
border-radius: 50%;
|
||||
background: conic-gradient(var(--danger) calc(var(--percentage) * 1%),
|
||||
var(--track) 0);
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.donut::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: calc(var(--size) - var(--thickness));
|
||||
height: calc(var(--size) - var(--thickness));
|
||||
border-radius: 50%;
|
||||
background: #fff;
|
||||
/* Inner cut-out */
|
||||
}
|
||||
|
||||
.donut span {
|
||||
position: absolute;
|
||||
font-size: calc(var(--size) / 6);
|
||||
}
|
||||
|
||||
/* Variants */
|
||||
.donut.thin {
|
||||
--size: 80px;
|
||||
--thickness: 12px;
|
||||
}
|
||||
|
||||
.donut.medium {
|
||||
--size: 120px;
|
||||
--thickness: 25px;
|
||||
}
|
||||
|
||||
.donut.large {
|
||||
--size: 180px;
|
||||
--thickness: 35px;
|
||||
}
|
||||
|
||||
/* Color variants */
|
||||
.donut-success {
|
||||
background: conic-gradient(var(--success) calc(var(--percentage) * 1%),
|
||||
var(--track) 0);
|
||||
color: var(--success)
|
||||
}
|
||||
|
||||
.donut-warning {
|
||||
background: conic-gradient(var(--warning) calc(var(--percentage) * 1%),
|
||||
var(--track) 0);
|
||||
color: var(--warning)
|
||||
}
|
||||
|
||||
.donut-danger {
|
||||
background: conic-gradient(var(--danger) calc(var(--percentage) * 1%),
|
||||
var(--track) 0);
|
||||
color: var(--danger)
|
||||
}
|
||||
|
||||
.donut-primary {
|
||||
background: conic-gradient(var(--primary) calc(var(--percentage) * 1%),
|
||||
var(--track) 0);
|
||||
color: var(--primary)
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<!-- Header -->
|
||||
<div class="header">
|
||||
<h1>Daily Progress Report</h1>
|
||||
<div class="project-info">
|
||||
<strong>Project:</strong> ANP ultimas wakad<br>
|
||||
<strong>Date:</strong> 17 September 2025
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Status Note -->
|
||||
<div class="status-note">
|
||||
* Project Status Reported - Generated at 18-Sep-2025 03:30:03 UTC
|
||||
</div>
|
||||
|
||||
<!-- Status Cards -->
|
||||
<div class="status-cards">
|
||||
<div class="card">
|
||||
<h4 class="card-title">TODAY'S ATTENDANCE</h4>
|
||||
<div style="display:flex; flex-wrap:wrap;">
|
||||
|
||||
<!-- Left Column -->
|
||||
<div style="width:50%; box-sizing:border-box;display:flex; justify-content:center; align-items:center;">
|
||||
<!-- Medium -->
|
||||
<div class="donut thin" style="--percentage: 66;">
|
||||
<span>20 / 30</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Right Column -->
|
||||
<div class="legend" style="width:50%; padding:15px; box-sizing:border-box;">
|
||||
<div class="legend-item"
|
||||
style="margin-bottom:10px;text-align: left; display:left; justify-content:left; align-items:left!important;">
|
||||
<span class="legend-color legend-green"></span> Completed
|
||||
</div>
|
||||
<div class="legend-item"
|
||||
style="margin-bottom:10px;text-align: left; display:left; justify-content:left; align-items:left!important;; ">
|
||||
<span class="legend-color legend-blue"></span> In Progress
|
||||
</div>
|
||||
<div class="legend-item"
|
||||
style="margin-bottom:10px; text-align: left; display:left; justify-content:left; align-items:left!important;;">
|
||||
<span class="legend-color legend-gray"></span> Pending
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<div style="padding:10px; text-align:center;">
|
||||
<p class="text-muted">Team members present on the site</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h4 class="card-title">DAILY TASKS COMPLETED</h4>
|
||||
<div style="display:flex; flex-wrap:wrap;">
|
||||
|
||||
<!-- Left Column -->
|
||||
<div style="width:50%; box-sizing:border-box;display:flex; justify-content:center; align-items:center;">
|
||||
<!-- Medium -->
|
||||
<div class="donut thin donut-primary" style="--percentage: 66;">
|
||||
<span>20 / 30</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Right Column -->
|
||||
<div class="legend" style="width:50%; padding:15px; box-sizing:border-box;">
|
||||
<div class="legend-item"
|
||||
style="margin-bottom:10px;text-align: left; display:left; justify-content:left; align-items:left!important;">
|
||||
<span class="legend-color legend-green"></span> Completed
|
||||
</div>
|
||||
<div class="legend-item"
|
||||
style="margin-bottom:10px;text-align: left; display:left; justify-content:left; align-items:left!important;; ">
|
||||
<span class="legend-color legend-blue"></span> In Progress
|
||||
</div>
|
||||
<div class="legend-item"
|
||||
style="margin-bottom:10px; text-align: left; display:left; justify-content:left; align-items:left!important;;">
|
||||
<span class="legend-color legend-gray"></span> Pending
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<div style="padding:10px; text-align:center;">
|
||||
<p class="text-muted">Team members present on the site</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h4 class="card-title">DAILY TASKS COMPLETED</h4>
|
||||
<p class="value tasks">20 / 30</p>
|
||||
<p>Team member present</p>
|
||||
<div class="legend">
|
||||
<div class="legend-item"><span class="legend-color legend-blue"></span> Completed</div>
|
||||
<div class="legend-item"><span class="legend-color legend-green"></span> In Progress</div>
|
||||
<div class="legend-item"><span class="legend-color legend-gray"></span> Pending</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h4 class="card-title">PROJECT COMPLETION STATUS</h4>
|
||||
<p class=" value completion">20 / 30</p>
|
||||
<p>Team member present</p>
|
||||
<div class="legend">
|
||||
<div class="legend-item"><span class="legend-color legend-green"></span> Completed</div>
|
||||
<div class="legend-item"><span class="legend-color legend-blue"></span> In Progress</div>
|
||||
<div class="legend-item"><span class="legend-color legend-gray"></span> Pending</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h4 class="card-title">Regularization Pending</h4>
|
||||
<p class="value tasks">28/32</p>
|
||||
<p class="text-muted">Regularization Pending</p>
|
||||
<div class="legend">
|
||||
<div class="legend-item"><span class="legend-color legend-green"></span> Completed</div>
|
||||
<div class="legend-item"><span class="legend-color legend-blue"></span> In Progress</div>
|
||||
<div class="legend-item"><span class="legend-color legend-gray"></span> Pending</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<!-- Row 1: Header -->
|
||||
<div>
|
||||
<h4 class="card-title">Checkout Pending</h4>
|
||||
</div>
|
||||
|
||||
<!-- Row 2: Two Columns -->
|
||||
<div style="display:flex; flex-wrap:wrap;">
|
||||
|
||||
<!-- Left Column -->
|
||||
<div style="width:50%; box-sizing:border-box;display:flex; justify-content:center; align-items:center;">
|
||||
<!-- Medium -->
|
||||
<div class="donut thin donut-success" style="--percentage: 73;">
|
||||
<span>73%</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Right Column -->
|
||||
<div class="legend" style="width:50%; padding:15px; box-sizing:border-box;">
|
||||
<div class="legend-item"
|
||||
style="margin-bottom:10px;text-align: left; display:left; justify-content:left; align-items:left!important;">
|
||||
<span class="legend-color legend-green"></span> Completed
|
||||
</div>
|
||||
<div class="legend-item"
|
||||
style="margin-bottom:10px;text-align: left; display:left; justify-content:left; align-items:left!important;; ">
|
||||
<span class="legend-color legend-blue"></span> In Progress
|
||||
</div>
|
||||
<div class="legend-item"
|
||||
style="margin-bottom:10px; text-align: left; display:left; justify-content:left; align-items:left!important;;">
|
||||
<span class="legend-color legend-gray"></span> Pending
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Row 3: Full Width -->
|
||||
<div>
|
||||
<div style="padding:10px; text-align:center;">
|
||||
<p class="text-muted">Team members present on the site</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div>
|
||||
<h4 class="card-title">Activity Report Pending</h4>
|
||||
</div>
|
||||
<div style="display:flex; flex-wrap:wrap;">
|
||||
|
||||
<!-- Left Column -->
|
||||
<div style="width:50%; box-sizing:border-box;display:flex; justify-content:center; align-items:center;">
|
||||
<!-- Medium -->
|
||||
<div class="donut thin donut-warning" style="--percentage: 0;">
|
||||
<span>0%</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Right Column -->
|
||||
<div class="legend" style="width:50%; padding:15px; box-sizing:border-box;">
|
||||
<div class="legend-item"
|
||||
style="margin-bottom:10px;text-align: left; display:left; justify-content:left; align-items:left!important;">
|
||||
<span class="legend-color legend-green"></span> Completed
|
||||
</div>
|
||||
<div class="legend-item"
|
||||
style="margin-bottom:10px;text-align: left; display:left; justify-content:left; align-items:left!important;; ">
|
||||
<span class="legend-color legend-blue"></span> In Progress
|
||||
</div>
|
||||
<div class="legend-item"
|
||||
style="margin-bottom:10px; text-align: left; display:left; justify-content:left; align-items:left!important;;">
|
||||
<span class="legend-color legend-gray"></span> Pending
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<div style="padding:10px; text-align:center;">
|
||||
<p class="text-muted">Team members present on the site</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<!-- Row 1: Header -->
|
||||
<div>
|
||||
<h4 class="card-title">Team Strength on Site</h4>
|
||||
</div>
|
||||
<table style="width: 100%;">
|
||||
<tr>
|
||||
<td style="text-align: left;">Site Engineer</td>
|
||||
<td style="text-align: right;">1</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: left;">Weilder</td>
|
||||
<td style="text-align: right;">15</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: left;">Helper</td>
|
||||
<td style="text-align: right;">2</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: left;">Painter</td>
|
||||
<td style="text-align: right;">1</td>
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activities -->
|
||||
<div class="activities">
|
||||
<h2>Activities (Tasks) Performed 17-Sep-2025</h2>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>NAME</th>
|
||||
<th>JOB ROLE</th>
|
||||
<th>CHECK IN</th>
|
||||
<th>CHECK OUT</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Siddharth Barde</td>
|
||||
<td>Site Engineer</td>
|
||||
<td>17-Sep-2025 11:47 AM</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Siddharth Barde</td>
|
||||
<td>Site Engineer</td>
|
||||
<td>17-Sep-2025 11:47 AM</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Siddharth Barde</td>
|
||||
<td>Site Engineer</td>
|
||||
<td>17-Sep-2025 11:47 AM</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="footer" style="display:flex; flex-wrap:wrap;">
|
||||
<div style="width: 50%;text-align: left;">
|
||||
Contact Us: contact[at]marcoaiot.com<br>
|
||||
Marco AIoT technologies Pvt. Ltd. ©2025 All Rights Reserved
|
||||
</div>
|
||||
|
||||
<div style="width: 50%; text-align: right;">
|
||||
<!-- <a href="#">Instagram</a> | -->
|
||||
<a href="#"><img src="https://cdn.marcoaiot.com/icons/brands/google.png" style="height: 15px;" /></a> |
|
||||
|
||||
<a href="#"><img src="https://cdn.marcoaiot.com/icons/brands/twitter.png" style="height: 15px;" /></a> |
|
||||
|
||||
<a href="#"><img src="https://cdn.marcoaiot.com/icons/brands/facebook.png" style="height: 15px;" /></a> |
|
||||
<a href="#"><img src="https://cdn.marcoaiot.com/icons/brands/instagram.png" style="height: 15px;" /></a>
|
||||
<!-- <a href="#"><img src="https://cdn.marcoaiot.com/icons/brands/youtube.png" style="height: 15px;" /></a> | <a
|
||||
href="#">LinkedIn</a> |
|
||||
<a href="#">YouTube</a> -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div style="text-align: center;width: 100%;background-color: #fff;margin:10px;font-size: small;color: #6c757d ;">
|
||||
You have received this email because it contains important information about your Marco PMS Account account.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
157
mailling/test mail sender/body.txt
Normal file
157
mailling/test mail sender/body.txt
Normal file
@ -0,0 +1,157 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>CSS Donut Variants</title>
|
||||
<style>
|
||||
.donut {
|
||||
--percentage: 65; /* Change this per chart */
|
||||
--primary: #e63946; /* Fill color */
|
||||
--track: #e9ecef; /* Background track */
|
||||
--size: 120px; /* Default size */
|
||||
--thickness: 20px; /* Default thickness */
|
||||
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
border-radius: 50%;
|
||||
background: conic-gradient(
|
||||
var(--primary) calc(var(--percentage) * 1%),
|
||||
var(--track) 0
|
||||
);
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.donut::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: calc(var(--size) - var(--thickness));
|
||||
height: calc(var(--size) - var(--thickness));
|
||||
border-radius: 50%;
|
||||
background: #fff; /* Inner cut-out */
|
||||
}
|
||||
|
||||
.donut span {
|
||||
position: absolute;
|
||||
font-size: calc(var(--size) / 6);
|
||||
}
|
||||
|
||||
/* Variants */
|
||||
.donut.thin {
|
||||
--size: 80px;
|
||||
--thickness: 12px;
|
||||
}
|
||||
.donut.medium {
|
||||
--size: 120px;
|
||||
--thickness: 25px;
|
||||
}
|
||||
.donut.large {
|
||||
--size: 180px;
|
||||
--thickness: 35px;
|
||||
}
|
||||
|
||||
|
||||
.progress {
|
||||
width: 100%;
|
||||
background-color: #e9ecef;
|
||||
border-radius: 0.375rem;
|
||||
overflow: hidden;
|
||||
height: 0.51rem; /* Default height */
|
||||
|
||||
margin-bottom: 1rem;
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 0.375rem; /* Default size */
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.progress.thin {
|
||||
height: 0.7rem;
|
||||
font-size: 0.6rem;
|
||||
|
||||
}
|
||||
.progress.medium {
|
||||
height: 1rem;
|
||||
font-size: 0.7rem;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.progress.large {
|
||||
height: 1.5rem;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
|
||||
.progress-bar {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
|
||||
background-color: #0d6efd; /* default = Bootstrap primary */
|
||||
transition: width 0.6s ease;
|
||||
}
|
||||
|
||||
/* Color variants */
|
||||
.progress-bar-success {
|
||||
background-color: #198754;
|
||||
}
|
||||
.progress-bar-warning {
|
||||
background-color: #ffc107;
|
||||
color: #000;
|
||||
}
|
||||
.progress-bar-danger {
|
||||
background-color: #dc3545;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="display:block; gap:40px; align-items:center; justify-content:center; min-height:100vh;">
|
||||
<div style="
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
">
|
||||
<!-- Thin -->
|
||||
<div class="donut thin" style="--percentage: 45;">
|
||||
<span>45%</span>
|
||||
</div>
|
||||
|
||||
<!-- Medium -->
|
||||
<div class="donut medium" style="--percentage: 73;">
|
||||
<span>73%</span>
|
||||
</div>
|
||||
|
||||
<!-- Large -->
|
||||
<div class="donut large" style="--percentage: 90;">
|
||||
<span>90%</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div style="
|
||||
margin-top: 100px;
|
||||
">
|
||||
<div class="progress" style="width:200px">
|
||||
<div class="progress-bar" style="width: 25%;">25%</div>
|
||||
</div>
|
||||
|
||||
<div class="progress thin " style="width:200px">
|
||||
<div class="progress-bar progress-bar-success" style="width: 50%;">50%</div>
|
||||
</div>
|
||||
|
||||
<div class="progress medium" style="width:200px">
|
||||
<div class="progress-bar progress-bar-warning" style="width: 75%;">75%</div>
|
||||
</div>
|
||||
|
||||
<div class="progress large" style="width:50%">
|
||||
<div class="progress-bar progress-bar-danger" style="width: 90%;">90%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
2670
python-email-sender/body copy 2.html
Normal file
2670
python-email-sender/body copy 2.html
Normal file
File diff suppressed because it is too large
Load Diff
636
python-email-sender/body copy.html
Normal file
636
python-email-sender/body copy.html
Normal file
File diff suppressed because one or more lines are too long
914
python-email-sender/body.html
Normal file
914
python-email-sender/body.html
Normal file
@ -0,0 +1,914 @@
|
||||
<!DOCTYPE HTML
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office">
|
||||
|
||||
<head>
|
||||
<!--[if gte mso 9]>
|
||||
<xml>
|
||||
<o:OfficeDocumentSettings>
|
||||
<o:AllowPNG/>
|
||||
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||
</o:OfficeDocumentSettings>
|
||||
</xml>
|
||||
<![endif]-->
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="x-apple-disable-message-reformatting">
|
||||
<!--[if !mso]><!-->
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"><!--<![endif]-->
|
||||
<title></title>
|
||||
|
||||
<style type="text/css">
|
||||
@media only screen and (min-width: 710px) {
|
||||
.u-row {
|
||||
width: 690px !important;
|
||||
}
|
||||
|
||||
.u-row .u-col {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
|
||||
.u-row .u-col-33p33 {
|
||||
width: 229.97699999999998px !important;
|
||||
}
|
||||
|
||||
|
||||
.u-row .u-col-50 {
|
||||
width: 345px !important;
|
||||
}
|
||||
|
||||
|
||||
.u-row .u-col-100 {
|
||||
width: 690px !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 710px) {
|
||||
.u-row-container {
|
||||
max-width: 100% !important;
|
||||
padding-left: 0px !important;
|
||||
padding-right: 0px !important;
|
||||
}
|
||||
|
||||
.u-row {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.u-row .u-col {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
min-width: 320px !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.u-row .u-col>div {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
||||
.u-row .u-col img {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
table,
|
||||
td,
|
||||
tr {
|
||||
border-collapse: collapse;
|
||||
vertical-align: top
|
||||
}
|
||||
|
||||
.ie-container table,
|
||||
.mso-container table {
|
||||
table-layout: fixed
|
||||
}
|
||||
|
||||
* {
|
||||
line-height: inherit
|
||||
}
|
||||
|
||||
a[x-apple-data-detectors=true] {
|
||||
color: inherit !important;
|
||||
text-decoration: none !important
|
||||
}
|
||||
|
||||
|
||||
table,
|
||||
td {
|
||||
color: #000000;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body class="clean-body u_body"
|
||||
style="margin: 0;padding: 0;-webkit-text-size-adjust: 100%;background-color: #F7F8F9;color: #000000">
|
||||
<!--[if IE]><div class="ie-container"><![endif]-->
|
||||
<!--[if mso]><div class="mso-container"><![endif]-->
|
||||
<table role="presentation"
|
||||
style="border-collapse: collapse;table-layout: fixed;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;vertical-align: top;min-width: 320px;Margin: 0 auto;background-color: #F7F8F9;width:100%"
|
||||
cellpadding="0" cellspacing="0">
|
||||
<tbody>
|
||||
<tr style="vertical-align: top">
|
||||
<td style="word-break: break-word;border-collapse: collapse !important;vertical-align: top">
|
||||
<!--[if (mso)|(IE)]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center" style="background-color: #F7F8F9;"><![endif]-->
|
||||
|
||||
|
||||
|
||||
<div class="u-row-container" style="padding: 1px 0px 0px;background-color: #b10000">
|
||||
<div class="u-row"
|
||||
style="margin: 0 auto;min-width: 320px;max-width: 690px;overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;">
|
||||
<div
|
||||
style="border-collapse: collapse;display: table;width: 100%;height: 100%;background-color: transparent;">
|
||||
<!--[if (mso)|(IE)]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding: 1px 0px 0px;background-color: #b10000;" align="center"><table role="presentation" cellpadding="0" cellspacing="0" border="0" style="width:690px;"><tr style="background-color: transparent;"><![endif]-->
|
||||
|
||||
<!--[if (mso)|(IE)]><td align="center" width="345" style="background-color: #b10000;width: 345px;padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;" valign="top"><![endif]-->
|
||||
<div class="u-col u-col-50"
|
||||
style="max-width: 320px;min-width: 345px;display: table-cell;vertical-align: top;">
|
||||
<div
|
||||
style="background-color: #b10000;height: 100%;width: 100% !important;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
<div
|
||||
style="box-sizing: border-box; height: 100%; padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--<![endif]-->
|
||||
|
||||
<table style="font-family:arial,helvetica,sans-serif;" role="presentation" cellpadding="0"
|
||||
cellspacing="0" width="100%" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="overflow-wrap:break-word;word-break:break-word;padding:15px 10px 10px 11px;font-family:arial,helvetica,sans-serif;"
|
||||
align="left">
|
||||
|
||||
<div>
|
||||
<h3 style="display: block;
|
||||
color: #ffffff;
|
||||
margin: 0;vertical-align:top;
|
||||
|
||||
font-size: 1.6em;
|
||||
margin-block-start: 0.67em;
|
||||
margin-block-end: 0.67em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
font-weight: bold; justify-content: space-between;
|
||||
unicode-bidi: isolate;">Daily Progress Report</h3>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
</div><!--<![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td><![endif]-->
|
||||
<!--[if (mso)|(IE)]><td align="center" width="345" style="background-color: #b10000;width: 345px;padding: 15px 1px 1px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;" valign="top"><![endif]-->
|
||||
<div class="u-col u-col-50"
|
||||
style="max-width: 320px;min-width: 345px;display: table-cell;vertical-align: top;">
|
||||
<div
|
||||
style="background-color: #b10000;height: 100%;width: 100% !important;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
<div
|
||||
style="box-sizing: border-box; height: 100%; padding: 15px 1px 1px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--<![endif]-->
|
||||
|
||||
<table style="font-family:arial,helvetica,sans-serif;" role="presentation" cellpadding="0"
|
||||
cellspacing="0" width="100%" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="overflow-wrap:break-word;word-break:break-word;padding:11px 10px 10px 27px;font-family:arial,helvetica,sans-serif;"
|
||||
align="left">
|
||||
|
||||
<div>
|
||||
<div class="project-info" style="color:#ffffff;text-align:right">
|
||||
<strong>Project:</strong> ANP ultimas wakad<br>
|
||||
<strong>Date:</strong> 17 September 2025
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
</div><!--<![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td><![endif]-->
|
||||
<!--[if (mso)|(IE)]></tr></table></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="u-row-container" style="padding: 0px;background-color: transparent">
|
||||
<div class="u-row"
|
||||
style="margin: 0 auto;min-width: 320px;max-width: 690px;overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;">
|
||||
<div
|
||||
style="border-collapse: collapse;display: table;width: 100%;height: 100%;background-color: transparent;">
|
||||
<!--[if (mso)|(IE)]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding: 0px;background-color: transparent;" align="center"><table role="presentation" cellpadding="0" cellspacing="0" border="0" style="width:690px;"><tr style="background-color: transparent;"><![endif]-->
|
||||
|
||||
<!--[if (mso)|(IE)]><td align="center" width="690" style="width: 690px;padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;" valign="top"><![endif]-->
|
||||
<div class="u-col u-col-100"
|
||||
style="max-width: 320px;min-width: 690px;display: table-cell;vertical-align: top;">
|
||||
<div
|
||||
style="height: 100%;width: 100% !important;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
<div
|
||||
style="box-sizing: border-box; height: 100%; padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--<![endif]-->
|
||||
|
||||
<table style="font-family:arial,helvetica,sans-serif;" role="presentation" cellpadding="0"
|
||||
cellspacing="0" width="100%" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="overflow-wrap:break-word;word-break:break-word;padding:10px;font-family:arial,helvetica,sans-serif;"
|
||||
align="left">
|
||||
|
||||
<!--[if mso]><table role="presentation" width="100%"><tr><td><![endif]-->
|
||||
<h4
|
||||
style="margin: 0px; line-height: 140%; text-align: left; word-wrap: break-word; font-size: 12px; font-weight: 400;">
|
||||
<span>* Project Stats Reported as 18-Sep-25 03:30:03 UTC <br>* Report is based on Data
|
||||
submitted on Date 17-Sep-25</span>
|
||||
</h4>
|
||||
<!--[if mso]></td></tr></table><![endif]-->
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
</div><!--<![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td><![endif]-->
|
||||
<!--[if (mso)|(IE)]></tr></table></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="u-row-container" style="padding: 0px;background-color: transparent">
|
||||
<div class="u-row"
|
||||
style="margin: 0 auto;min-width: 320px;max-width: 690px;overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;">
|
||||
<div
|
||||
style="border-collapse: collapse;display: table;width: 100%;height: 100%;background-color: transparent;">
|
||||
<!--[if (mso)|(IE)]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding: 0px;background-color: transparent;" align="center"><table role="presentation" cellpadding="0" cellspacing="0" border="0" style="width:690px;"><tr style="background-color: transparent;"><![endif]-->
|
||||
|
||||
<!--[if (mso)|(IE)]><td align="center" width="230" style="width: 230px;padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;" valign="top"><![endif]-->
|
||||
<div class="u-col u-col-33p33"
|
||||
style="max-width: 320px;min-width: 230px;display: table-cell;vertical-align: top;">
|
||||
<div
|
||||
style="height: 100%;width: 100% !important;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
<div
|
||||
style="box-sizing: border-box; height: 100%; padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--<![endif]-->
|
||||
|
||||
<table style="font-family:arial,helvetica,sans-serif;" role="presentation" cellpadding="0"
|
||||
cellspacing="0" width="100%" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="overflow-wrap:break-word;word-break:break-word;padding:10px;font-family:arial,helvetica,sans-serif;"
|
||||
align="left">
|
||||
|
||||
<div>
|
||||
<div class="card" style=" flex: 1;
|
||||
min-width: 200px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.2s
|
||||
ease, box-shadow 0.2s
|
||||
ease;
|
||||
border-top: 1px solid #e63946;">
|
||||
<h4 class="card-title" style=" font-size: 0.9rem;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
color: #6c757d;">Regularization Pending</h4>
|
||||
<p class="value tasks"
|
||||
style="font-size: 22px; font-weight: bold; color: rgb(0, 123, 255); line-height: inherit; margin: 0px;">
|
||||
28/32</p>
|
||||
<img src="https://cdn.marcoaiot.com/mailcontent/donut-chart.png">
|
||||
<p class="text-muted" style="line-height: inherit; margin: 0px;">Regularization
|
||||
Pending</p>
|
||||
<div class="legend" style=" margin-top: 10px;
|
||||
display: flex
|
||||
;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: #555;">
|
||||
<div class="legend-item" style="display: flex
|
||||
;
|
||||
align-items: center;
|
||||
gap: 4px;"><span class="legend-color legend-green" style="width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 2px;
|
||||
display: inline-block;background: #28a745;"></span> Completed
|
||||
</div>
|
||||
<div class="legend-item" style="display: flex
|
||||
;
|
||||
align-items: center;
|
||||
gap: 4px;"><span class="legend-color legend-blue" style="width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 2px;
|
||||
display: inline-block;background: #007bff;"></span> In Progress
|
||||
</div>
|
||||
<div class="legend-item" style="display: flex
|
||||
;
|
||||
align-items: center;
|
||||
gap: 4px;"><span class="legend-color legend-gray" style="width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 2px;
|
||||
display: inline-block;background: #ccc;"></span> Pending
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
</div><!--<![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td><![endif]-->
|
||||
<!--[if (mso)|(IE)]><td align="center" width="230" style="width: 230px;padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;" valign="top"><![endif]-->
|
||||
<div class="u-col u-col-33p33"
|
||||
style="max-width: 320px;min-width: 230px;display: table-cell;vertical-align: top;">
|
||||
<div
|
||||
style="height: 100%;width: 100% !important;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
<div
|
||||
style="box-sizing: border-box; height: 100%; padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--<![endif]-->
|
||||
|
||||
<table style="font-family:arial,helvetica,sans-serif;" role="presentation" cellpadding="0"
|
||||
cellspacing="0" width="100%" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="overflow-wrap:break-word;word-break:break-word;padding:10px;font-family:arial,helvetica,sans-serif;"
|
||||
align="left">
|
||||
|
||||
<div>
|
||||
<div class="card" style=" flex: 1;
|
||||
min-width: 200px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.2s
|
||||
ease, box-shadow 0.2s
|
||||
ease;
|
||||
border-top: 1px solid #e63946;">
|
||||
<h4 class="card-title" style=" font-size: 0.9rem;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
color: #6c757d;">DAILY TASKS COMPLETED
|
||||
</h4>
|
||||
<p class="value tasks"
|
||||
style="font-size: 22px; font-weight: bold; color: rgb(0, 123, 255); line-height: inherit; margin: 0px;">
|
||||
28/32</p>
|
||||
<img src="https://cdn.marcoaiot.com/mailcontent/donut-chart.png">
|
||||
<p class="text-muted" style="line-height: inherit; margin: 0px;">Team members present
|
||||
on the site</p>
|
||||
<div class="legend" style=" margin-top: 10px;
|
||||
display: flex
|
||||
;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: #555;">
|
||||
<div class="legend-item" style="display: flex
|
||||
;
|
||||
align-items: center;
|
||||
gap: 4px;"><span class="legend-color legend-green" style="width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 2px;
|
||||
display: inline-block;background: #28a745;"></span> Completed
|
||||
</div>
|
||||
<div class="legend-item" style="display: flex
|
||||
;
|
||||
align-items: center;
|
||||
gap: 4px;"><span class="legend-color legend-blue" style="width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 2px;
|
||||
display: inline-block;background: #007bff;"></span> In Progress
|
||||
</div>
|
||||
<div class="legend-item" style="display: flex
|
||||
;
|
||||
align-items: center;
|
||||
gap: 4px;"><span class="legend-color legend-gray" style="width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 2px;
|
||||
display: inline-block;background: #ccc;"></span> Pending
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
</div><!--<![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td><![endif]-->
|
||||
<!--[if (mso)|(IE)]><td align="center" width="230" style="width: 230px;padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;" valign="top"><![endif]-->
|
||||
<div class="u-col u-col-33p33"
|
||||
style="max-width: 320px;min-width: 230px;display: table-cell;vertical-align: top;">
|
||||
<div
|
||||
style="height: 100%;width: 100% !important;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
<div
|
||||
style="box-sizing: border-box; height: 100%; padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--<![endif]-->
|
||||
|
||||
<table style="font-family:arial,helvetica,sans-serif;" role="presentation" cellpadding="0"
|
||||
cellspacing="0" width="100%" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="overflow-wrap:break-word;word-break:break-word;padding:10px;font-family:arial,helvetica,sans-serif;"
|
||||
align="left">
|
||||
|
||||
<div>
|
||||
<div class="card" style=" flex: 1;
|
||||
min-width: 200px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.2s
|
||||
ease, box-shadow 0.2s
|
||||
ease;
|
||||
border-top: 1px solid #e63946;">
|
||||
<h4 class="card-title" style=" font-size: 0.9rem;
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
color: #6c757d;">Project Completed</h4>
|
||||
<p class="value tasks"
|
||||
style="font-size: 22px; font-weight: bold; color: rgb(0, 123, 255); line-height: inherit; margin: 0px;">
|
||||
28/32</p>
|
||||
<img src="https://cdn.marcoaiot.com/mailcontent/donut-chart.png">
|
||||
<p class="text-muted" style="line-height: inherit; margin: 0px;">PROJECT COMPLETION
|
||||
STATUS</p>
|
||||
<div class="legend" style=" margin-top: 10px;
|
||||
display: flex
|
||||
;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: #555;">
|
||||
<div class="legend-item" style="display: flex
|
||||
;
|
||||
align-items: center;
|
||||
gap: 4px;"><span class="legend-color legend-green" style="width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 2px;
|
||||
display: inline-block;background: #28a745;"></span> Completed
|
||||
</div>
|
||||
<div class="legend-item" style="display: flex
|
||||
;
|
||||
align-items: center;
|
||||
gap: 4px;"><span class="legend-color legend-blue" style="width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 2px;
|
||||
display: inline-block;background: #007bff;"></span> In Progress
|
||||
</div>
|
||||
<div class="legend-item" style="display: flex
|
||||
;
|
||||
align-items: center;
|
||||
gap: 4px;"><span class="legend-color legend-gray" style="width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 2px;
|
||||
display: inline-block;background: #ccc;"></span> Pending
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
</div><!--<![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td><![endif]-->
|
||||
<!--[if (mso)|(IE)]></tr></table></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="u-row-container" style="padding: 0px;background-color: transparent">
|
||||
<div class="u-row"
|
||||
style="margin: 0 auto;min-width: 320px;max-width: 690px;overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;">
|
||||
<div
|
||||
style="border-collapse: collapse;display: table;width: 100%;height: 100%;background-color: transparent;">
|
||||
<!--[if (mso)|(IE)]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding: 0px;background-color: transparent;" align="center"><table role="presentation" cellpadding="0" cellspacing="0" border="0" style="width:690px;"><tr style="background-color: transparent;"><![endif]-->
|
||||
|
||||
<!--[if (mso)|(IE)]><td align="center" width="690" style="width: 690px;padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;" valign="top"><![endif]-->
|
||||
<div class="u-col u-col-100"
|
||||
style="max-width: 320px;min-width: 690px;display: table-cell;vertical-align: top;">
|
||||
<div
|
||||
style="height: 100%;width: 100% !important;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
<div
|
||||
style="box-sizing: border-box; height: 100%; padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--<![endif]-->
|
||||
|
||||
<table style="font-family:arial,helvetica,sans-serif;" role="presentation" cellpadding="0"
|
||||
cellspacing="0" width="100%" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="overflow-wrap:break-word;word-break:break-word;padding:10px;font-family:arial,helvetica,sans-serif;"
|
||||
align="left">
|
||||
|
||||
<!--[if mso]><table role="presentation" width="100%"><tr><td><![endif]-->
|
||||
<h4
|
||||
style="margin: 0px; line-height: 140%; text-align: left; word-wrap: break-word; font-size: 16px; font-weight: 400;">
|
||||
<span>Activities (Tasks PErformed on 17-Sep-2025</span>
|
||||
</h4>
|
||||
<!--[if mso]></td></tr></table><![endif]-->
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
</div><!--<![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td><![endif]-->
|
||||
<!--[if (mso)|(IE)]></tr></table></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="u-row-container" style="padding: 0px;background-color: transparent">
|
||||
<div class="u-row"
|
||||
style="margin: 0 auto;min-width: 320px;max-width: 690px;overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;">
|
||||
<div
|
||||
style="border-collapse: collapse;display: table;width: 100%;height: 100%;background-color: transparent;">
|
||||
<!--[if (mso)|(IE)]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding: 0px;background-color: transparent;" align="center"><table role="presentation" cellpadding="0" cellspacing="0" border="0" style="width:690px;"><tr style="background-color: transparent;"><![endif]-->
|
||||
|
||||
<!--[if (mso)|(IE)]><td align="center" width="690" style="width: 690px;padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;" valign="top"><![endif]-->
|
||||
<div class="u-col u-col-100"
|
||||
style="max-width: 320px;min-width: 690px;display: table-cell;vertical-align: top;">
|
||||
<div
|
||||
style="height: 100%;width: 100% !important;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
<div
|
||||
style="box-sizing: border-box; height: 100%; padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--<![endif]-->
|
||||
|
||||
<table style="font-family:arial,helvetica,sans-serif;" role="presentation" cellpadding="0"
|
||||
cellspacing="0" width="100%" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="overflow-wrap:break-word;word-break:break-word;padding:10px;font-family:arial,helvetica,sans-serif;"
|
||||
align="left">
|
||||
|
||||
<table
|
||||
style="width: 100%; border-collapse: collapse; table-layout: fixed; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC; background-color: #FFFFFF;">
|
||||
|
||||
<thead>
|
||||
|
||||
<tr>
|
||||
|
||||
<th
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC; background-color: #DDDDDD; font-size: 14px; font-weight: 700; text-align: left;">
|
||||
<p>Name</p>
|
||||
</th>
|
||||
|
||||
<th
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC; background-color: #DDDDDD; font-size: 14px; font-weight: 700; text-align: left;">
|
||||
<p>Job Role</p>
|
||||
</th>
|
||||
|
||||
<th
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC; background-color: #DDDDDD; font-size: 14px; font-weight: 700; text-align: left;">
|
||||
</th>
|
||||
|
||||
<th
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC; background-color: #DDDDDD; font-size: 14px; font-weight: 700; text-align: left;">
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
<tbody style="font-size: 14px;text-align: left;line-height: 140%;">
|
||||
|
||||
<tr>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
<p>Siddharth Badre</p>
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
</div><!--<![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td><![endif]-->
|
||||
<!--[if (mso)|(IE)]></tr></table></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="u-row-container" style="padding: 0px;background-color: transparent">
|
||||
<div class="u-row"
|
||||
style="margin: 0 auto;min-width: 320px;max-width: 690px;overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;">
|
||||
<div
|
||||
style="border-collapse: collapse;display: table;width: 100%;height: 100%;background-color: transparent;">
|
||||
<!--[if (mso)|(IE)]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding: 0px;background-color: transparent;" align="center"><table role="presentation" cellpadding="0" cellspacing="0" border="0" style="width:690px;"><tr style="background-color: transparent;"><![endif]-->
|
||||
|
||||
<!--[if (mso)|(IE)]><td align="center" width="690" style="width: 690px;padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;" valign="top"><![endif]-->
|
||||
<div class="u-col u-col-100"
|
||||
style="max-width: 320px;min-width: 690px;display: table-cell;vertical-align: top;">
|
||||
<div
|
||||
style="height: 100%;width: 100% !important;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
<div
|
||||
style="box-sizing: border-box; height: 100%; padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--<![endif]-->
|
||||
|
||||
<table style="font-family:arial,helvetica,sans-serif;" role="presentation" cellpadding="0"
|
||||
cellspacing="0" width="100%" border="0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td
|
||||
style="overflow-wrap:break-word;word-break:break-word;padding:10px;font-family:arial,helvetica,sans-serif;"
|
||||
align="left">
|
||||
|
||||
<table
|
||||
style="width: 100%; border-collapse: collapse; table-layout: fixed; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC; background-color: #FFFFFF;">
|
||||
|
||||
<thead>
|
||||
|
||||
<tr>
|
||||
|
||||
<th
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC; background-color: #DDDDDD; font-size: 14px; font-weight: 700; text-align: left;">
|
||||
<p>Add header text</p>
|
||||
</th>
|
||||
|
||||
<th
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC; background-color: #DDDDDD; font-size: 14px; font-weight: 700; text-align: left;">
|
||||
</th>
|
||||
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
|
||||
<tbody style="font-size: 14px;text-align: left;line-height: 140%;">
|
||||
|
||||
<tr>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
<p>Add text</p>
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
<td
|
||||
style="padding: 10px; border-top-width: 1px; border-top-style: solid; border-top-color: #CCC; border-left-width: 1px; border-left-style: solid; border-left-color: #CCC; border-right-width: 1px; border-right-style: solid; border-right-color: #CCC; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: #CCC;">
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
</div><!--<![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td><![endif]-->
|
||||
<!--[if (mso)|(IE)]></tr></table></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="u-row-container" style="padding: 0px;background-color: transparent">
|
||||
<div class="u-row"
|
||||
style="margin: 0 auto;min-width: 320px;max-width: 690px;overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;">
|
||||
<div
|
||||
style="border-collapse: collapse;display: table;width: 100%;height: 100%;background-color: transparent;">
|
||||
<!--[if (mso)|(IE)]><table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding: 0px;background-color: transparent;" align="center"><table role="presentation" cellpadding="0" cellspacing="0" border="0" style="width:690px;"><tr style="background-color: transparent;"><![endif]-->
|
||||
|
||||
<!--[if (mso)|(IE)]><td align="center" width="690" style="width: 690px;padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;" valign="top"><![endif]-->
|
||||
<div class="u-col u-col-100"
|
||||
style="max-width: 320px;min-width: 690px;display: table-cell;vertical-align: top;">
|
||||
<div
|
||||
style="height: 100%;width: 100% !important;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
<div
|
||||
style="box-sizing: border-box; height: 100%; padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;border-radius: 0px;-webkit-border-radius: 0px; -moz-border-radius: 0px;">
|
||||
<!--<![endif]-->
|
||||
|
||||
<!--[if (!mso)&(!IE)]><!-->
|
||||
</div><!--<![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
<!--[if (mso)|(IE)]></td><![endif]-->
|
||||
<!--[if (mso)|(IE)]></tr></table></td></tr></table><![endif]-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!--[if (mso)|(IE)]></td></tr></table><![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--[if mso]></div><![endif]-->
|
||||
<!--[if IE]></div><![endif]-->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
10
python-email-sender/config.json
Normal file
10
python-email-sender/config.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"EMAIL_CONFIGURATION": {
|
||||
"EMAIL_HOST": "mail.marcoaiot.com",
|
||||
"EMAIL_PORT": 587,
|
||||
"EMAIL_USER": "admin@marcoaiot.com",
|
||||
"EMAIL_PASS": "xxx",
|
||||
"EMAIL_SUBJECT": "Database backup process",
|
||||
"EMAIL_RECEIVERS": "vikas@marcoaiot.com,umesh@marcoaiot.com"
|
||||
}
|
||||
}
|
||||
84
python-email-sender/mail-sender-with-charts.py
Normal file
84
python-email-sender/mail-sender-with-charts.py
Normal file
@ -0,0 +1,84 @@
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.image import MIMEImage
|
||||
import os
|
||||
import cairosvg
|
||||
|
||||
def generate_donut_svg(percentage, color="#0d6efd", size=120, thickness=4):
|
||||
"""
|
||||
Generate an inline SVG donut chart.
|
||||
"""
|
||||
svg = f"""
|
||||
<svg width="{size}" height="{size}" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Track -->
|
||||
<path
|
||||
d="M18 2.0845
|
||||
a 15.9155 15.9155 0 0 1 0 31.831
|
||||
a 15.9155 15.9155 0 0 1 0 -31.831"
|
||||
fill="none"
|
||||
stroke="#e9ecef"
|
||||
stroke-width="{thickness}"
|
||||
/>
|
||||
<!-- Progress -->
|
||||
<path
|
||||
d="M18 2.0845
|
||||
a 15.9155 15.9155 0 0 1 0 31.831
|
||||
a 15.9155 15.9155 0 0 1 0 -31.831"
|
||||
fill="none"
|
||||
stroke="{color}"
|
||||
stroke-width="{thickness}"
|
||||
stroke-dasharray="{percentage}, 100"
|
||||
/>
|
||||
<!-- Label -->
|
||||
<text x="18" y="20.35" fill="#333" font-size="5" text-anchor="middle">{percentage}%</text>
|
||||
</svg>
|
||||
"""
|
||||
return svg
|
||||
|
||||
# Sender and receiver
|
||||
sender_email = "marcoioitsoft@gmail.com"
|
||||
receiver_emails = ["vikasnale@gmail.com", "vikas@marcoaiot.com", "umeshvdesai@outlook.com"]
|
||||
password = "qrtq wfuj hwpp fhqr" # Use Gmail App Password here
|
||||
|
||||
# Read HTML body from file
|
||||
file_path = os.path.join(os.path.dirname(__file__), "body.txt")
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
body = f.read()
|
||||
|
||||
# Create the email
|
||||
message = MIMEMultipart("related")
|
||||
message["From"] = sender_email
|
||||
message["To"] = ", ".join(receiver_emails)
|
||||
message["Subject"] = "Test HTML Email with Donut Charts"
|
||||
|
||||
# Generate SVGs and convert to PNGs
|
||||
donut_svgs = [
|
||||
generate_donut_svg(45, "#e63946"),
|
||||
generate_donut_svg(73, "#0d6efd"),
|
||||
generate_donut_svg(90, "#198754")
|
||||
]
|
||||
|
||||
# Attach donuts as inline images
|
||||
for i, svg in enumerate(donut_svgs, start=1):
|
||||
png_bytes = cairosvg.svg2png(bytestring=svg.encode("utf-8"))
|
||||
img = MIMEImage(png_bytes, "png")
|
||||
cid = f"donut{i}"
|
||||
img.add_header("Content-ID", f"<{cid}>")
|
||||
message.attach(img)
|
||||
body += f'<br><img src="cid:{cid}" alt="Donut{i}">'
|
||||
|
||||
# Attach the final HTML body
|
||||
message.attach(MIMEText(f"<html><body>{body}</body></html>", "html"))
|
||||
|
||||
# Send the email
|
||||
try:
|
||||
server = smtplib.SMTP("smtp.gmail.com", 587)
|
||||
server.starttls()
|
||||
server.login(sender_email, password)
|
||||
server.sendmail(sender_email, receiver_emails, message.as_string())
|
||||
print("✅ Email sent successfully with embedded donut PNGs!")
|
||||
except Exception as e:
|
||||
print("❌ Error:", e)
|
||||
finally:
|
||||
server.quit()
|
||||
89
python-email-sender/multipart-email.py
Normal file
89
python-email-sender/multipart-email.py
Normal file
@ -0,0 +1,89 @@
|
||||
import smtplib
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.image import MIMEImage
|
||||
from email.mime.base import MIMEBase
|
||||
from email import encoders
|
||||
|
||||
# --- Email Configuration ---
|
||||
# Replace with your actual email and app password
|
||||
sender_password = "qrtq wfuj hwpp fhqr"
|
||||
recipient_email =["vikasnale@gmail.com", "vikas@marcoaiot.com", "umeshvdesai@outlook.com"]
|
||||
sender_email = "marcoioitsoft@gmail.com"
|
||||
receiver_emails = ["vikasnale@gmail.com", "vikas@marcoaiot.com"]
|
||||
password = "qrtq wfuj hwpp fhqr" # Use Gmail App Password here
|
||||
|
||||
# --- 1. Create the top-level container (multipart/related) ---
|
||||
# This container will hold the HTML body and the embedded images.
|
||||
msg_root = MIMEMultipart('related')
|
||||
msg_root['Subject'] = 'Python Email with Embedded Images and Attachment'
|
||||
msg_root['From'] = sender_email
|
||||
msg_root['To'] = recipient_email
|
||||
msg_root.preamble = 'This is a multi-part message in MIME format.'
|
||||
|
||||
# --- 2. Create the alternative container (multipart/alternative) ---
|
||||
# This part holds both the plain-text and HTML versions of the email content.
|
||||
msg_alternative = MIMEMultipart('alternative')
|
||||
msg_root.attach(msg_alternative)
|
||||
|
||||
# --- Define the plain text and HTML content ---
|
||||
plain_text_content = """\
|
||||
Hello,
|
||||
This is the plain text version of the email.
|
||||
The images are not visible here.
|
||||
Please view this email in a client that supports HTML to see the embedded images.
|
||||
"""
|
||||
|
||||
html_content = """\
|
||||
<html>
|
||||
<body>
|
||||
<p>Hello,</p>
|
||||
<p>This email contains two embedded images and one regular attachment.</p>
|
||||
<p>Here is the first image (CID):</p>
|
||||
<img src="cid:image1.jpg" alt="First Image">
|
||||
<p>And here is the second one (CID):</p>
|
||||
<img src="cid:logo.png" alt="Company Logo">
|
||||
<p>Please see the attached PDF for more information.</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
# Attach the plain text and HTML versions to the alternative container
|
||||
msg_alternative.attach(MIMEText(plain_text_content, 'plain'))
|
||||
msg_alternative.attach(MIMEText(html_content, 'html'))
|
||||
|
||||
# --- 3. Attach the embedded images with Content-ID (CID) ---
|
||||
# The Content-ID is crucial for the HTML body to reference the image.
|
||||
# The 'inline' disposition makes sure the image is displayed within the email body.
|
||||
|
||||
# Attach 'image1.jpg'
|
||||
with open('image1.jpg', 'rb') as fp:
|
||||
msg_image1 = MIMEImage(fp.read(), _subtype="jpeg")
|
||||
msg_image1.add_header('Content-ID', '<image1.jpg>')
|
||||
msg_image1.add_header('Content-Disposition', 'inline')
|
||||
msg_root.attach(msg_image1)
|
||||
|
||||
# Attach 'logo.png'
|
||||
with open('logo.png', 'rb') as fp:
|
||||
msg_logo = MIMEImage(fp.read(), _subtype="png")
|
||||
msg_logo.add_header('Content-ID', '<logo.png>')
|
||||
msg_logo.add_header('Content-Disposition', 'inline')
|
||||
msg_root.attach(msg_logo)
|
||||
|
||||
# --- 4. Attach the regular attachment ---
|
||||
# This part is for the file that should be a standard attachment.
|
||||
with open('document.pdf', 'rb') as fp:
|
||||
part = MIMEBase('application', 'pdf')
|
||||
part.set_payload(fp.read())
|
||||
encoders.encode_base64(part)
|
||||
part.add_header('Content-Disposition', 'attachment', filename='document.pdf')
|
||||
msg_root.attach(part)
|
||||
|
||||
# --- 5. Send the email using SMTP ---
|
||||
try:
|
||||
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
|
||||
smtp.login(sender_email, sender_password)
|
||||
smtp.send_message(msg_root)
|
||||
print("Email sent successfully!")
|
||||
except Exception as e:
|
||||
print(f"Failed to send email: {e}")
|
||||
35
python-email-sender/test-mail-sender-body-file.py
Normal file
35
python-email-sender/test-mail-sender-body-file.py
Normal file
@ -0,0 +1,35 @@
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
import os
|
||||
|
||||
# Sender and receiver
|
||||
sender_email = "marcoioitsoft@gmail.com"
|
||||
receiver_emails = ["garu.vikas@gmail.com", "vikas@marcoaiot.com" ,"umeshvdesai@outlook.com"]
|
||||
password = "qrtq wfuj hwpp fhqr" # Use Gmail App Password here
|
||||
|
||||
# Read body from text file (e.g., body.txt in the same folder)
|
||||
file_path = os.path.join(os.path.dirname(__file__), "body.html")
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
body = f.read()
|
||||
|
||||
# Create the email
|
||||
message = MIMEMultipart()
|
||||
message["From"] = sender_email
|
||||
message["To"] =", ".join(receiver_emails)
|
||||
message["Subject"] = "Test Email from Python"
|
||||
|
||||
# Attach body
|
||||
message.attach(MIMEText(body, "html"))
|
||||
|
||||
try:
|
||||
# Connect to Gmail SMTP server
|
||||
server = smtplib.SMTP("smtp.gmail.com", 587)
|
||||
server.starttls() # Secure the connection
|
||||
server.login(sender_email, password)
|
||||
server.sendmail(sender_email, receiver_emails, message.as_string())
|
||||
print("✅ Email sent successfully!")
|
||||
except Exception as e:
|
||||
print("❌ Error:", e)
|
||||
finally:
|
||||
server.quit()
|
||||
84
python-email-sender/test-mail-sender.py
Normal file
84
python-email-sender/test-mail-sender.py
Normal file
@ -0,0 +1,84 @@
|
||||
import smtplib
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.image import MIMEImage
|
||||
import os
|
||||
import cairosvg
|
||||
|
||||
def generate_donut_svg(percentage, color="#0d6efd", size=120, thickness=4):
|
||||
"""
|
||||
Generate an inline SVG donut chart.
|
||||
"""
|
||||
svg = f"""
|
||||
<svg width="{size}" height="{size}" viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Track -->
|
||||
<path
|
||||
d="M18 2.0845
|
||||
a 15.9155 15.9155 0 0 1 0 31.831
|
||||
a 15.9155 15.9155 0 0 1 0 -31.831"
|
||||
fill="none"
|
||||
stroke="#e9ecef"
|
||||
stroke-width="{thickness}"
|
||||
/>
|
||||
<!-- Progress -->
|
||||
<path
|
||||
d="M18 2.0845
|
||||
a 15.9155 15.9155 0 0 1 0 31.831
|
||||
a 15.9155 15.9155 0 0 1 0 -31.831"
|
||||
fill="none"
|
||||
stroke="{color}"
|
||||
stroke-width="{thickness}"
|
||||
stroke-dasharray="{percentage}, 100"
|
||||
/>
|
||||
<!-- Label -->
|
||||
<text x="18" y="20.35" fill="#333" font-size="5" text-anchor="middle">{percentage}%</text>
|
||||
</svg>
|
||||
"""
|
||||
return svg
|
||||
|
||||
# Sender and receiver
|
||||
sender_email = "marcoioitsoft@gmail.com"
|
||||
receiver_emails = ["vikasnale@gmail.com", "vikas@marcoaiot.com", "umeshvdesai@outlook.com"]
|
||||
password = "qrtq wfuj hwpp fhqr" # Use Gmail App Password here
|
||||
|
||||
# Read HTML body from file
|
||||
file_path = os.path.join(os.path.dirname(__file__), "body.txt")
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
body = f.read()
|
||||
|
||||
# Create the email
|
||||
message = MIMEMultipart("related")
|
||||
message["From"] = sender_email
|
||||
message["To"] = ", ".join(receiver_emails)
|
||||
message["Subject"] = "Test HTML Email with Donut Charts"
|
||||
|
||||
# Generate SVGs and convert to PNGs
|
||||
donut_svgs = [
|
||||
generate_donut_svg(45, "#e63946"),
|
||||
generate_donut_svg(73, "#0d6efd"),
|
||||
generate_donut_svg(90, "#198754")
|
||||
]
|
||||
|
||||
# Attach donuts as inline images
|
||||
for i, svg in enumerate(donut_svgs, start=1):
|
||||
png_bytes = cairosvg.svg2png(bytestring=svg.encode("utf-8"))
|
||||
img = MIMEImage(png_bytes, "png")
|
||||
cid = f"donut{i}"
|
||||
img.add_header("Content-ID", f"<{cid}>")
|
||||
message.attach(img)
|
||||
body += f'<br><img src="cid:{cid}" alt="Donut{i}">'
|
||||
|
||||
# Attach the final HTML body
|
||||
message.attach(MIMEText(f"<html><body>{body}</body></html>", "html"))
|
||||
|
||||
# Send the email
|
||||
try:
|
||||
server = smtplib.SMTP("smtp.gmail.com", 587)
|
||||
server.starttls()
|
||||
server.login(sender_email, password)
|
||||
server.sendmail(sender_email, receiver_emails, message.as_string())
|
||||
print("✅ Email sent successfully with embedded donut PNGs!")
|
||||
except Exception as e:
|
||||
print("❌ Error:", e)
|
||||
finally:
|
||||
server.quit()
|
||||
11
python-process-monitor/.env
Normal file
11
python-process-monitor/.env
Normal file
@ -0,0 +1,11 @@
|
||||
# Services & Containers
|
||||
SERVICES=nginx,rocketchat,mongod,mysql
|
||||
CONTAINERS=redmine-app,mediawiki-app,sonarqube,postgres-sonar,ecc269bb3ba3
|
||||
|
||||
# Mail settings
|
||||
SENDER_EMAIL=marcoioitsoft@gmail.com
|
||||
RECEIVER_EMAIL=umesh@marcoaiot.com,vikas@marcoaiot.com
|
||||
SMTP_SERVER=smtp.gmail.com
|
||||
SMTP_PORT=587
|
||||
SMTP_USER=marcoioitsoft@gmail.com
|
||||
SMTP_PASSWORD=qrtq wfuj hwpp fhqr
|
||||
114
python-process-monitor/python-process-monitor.py
Normal file
114
python-process-monitor/python-process-monitor.py
Normal file
@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import subprocess
|
||||
import smtplib
|
||||
import os
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
# ----------------- CONFIG -----------------
|
||||
services = os.getenv("SERVICES", "").split(",")
|
||||
containers = os.getenv("CONTAINERS", "").split(",") # update with your container names
|
||||
|
||||
sender_email = os.getenv("SENDER_EMAIL", "")
|
||||
receiver_email =os.getenv("RECEIVER_EMAIL", "").split(",")
|
||||
smtp_server = os.getenv("SMTP_SERVER", "")
|
||||
smtp_port = os.getenv("SMTP_PORT", "")
|
||||
smtp_user = os.getenv("SMTP_USER", "")
|
||||
smtp_password = os.getenv("SMTP_PASSWORD", "")
|
||||
# ------------------------------------------
|
||||
|
||||
def run_cmd(cmd):
|
||||
return subprocess.getoutput(cmd)
|
||||
|
||||
def check_service(service):
|
||||
status = subprocess.run(["systemctl", "is-active", service], capture_output=True, text=True)
|
||||
if status.returncode == 0:
|
||||
return True, ""
|
||||
else:
|
||||
for attempt in range(2):
|
||||
print("Attempting to start: " + service)
|
||||
subprocess.run(["systemctl", "restart", service])
|
||||
status = subprocess.run(["systemctl", "is-active", service], capture_output=True, text=True)
|
||||
if status.returncode == 0:
|
||||
return True, ""
|
||||
logs = run_cmd(f"journalctl -u {service} -n 20 --no-pager")
|
||||
return False, logs
|
||||
|
||||
def check_container(container):
|
||||
status = run_cmd(f"docker inspect -f '{{{{.State.Running}}}}' {container}")
|
||||
if status.strip() == "true":
|
||||
return True, ""
|
||||
else:
|
||||
for attempt in range(2):
|
||||
run_cmd(f"docker restart {container}")
|
||||
status = run_cmd(f"docker inspect -f '{{{{.State.Running}}}}' {container}")
|
||||
if status.strip() == "true":
|
||||
return True, ""
|
||||
logs = run_cmd(f"docker logs --tail 20 {container}")
|
||||
return False, logs
|
||||
|
||||
def send_email(failures):
|
||||
if not failures:
|
||||
return
|
||||
|
||||
msg = MIMEMultipart("alternative")
|
||||
msg["From"] = sender_email
|
||||
msg["To"] = ", ".join(receiver_email)
|
||||
msg["Subject"] = "Service/Container Failure Report"
|
||||
|
||||
# HTML Email Body
|
||||
html = """
|
||||
<html>
|
||||
<body style="font-family: Arial, sans-serif; background-color: #f8f9fa; padding: 20px;">
|
||||
<h2 style="color: #dc3545;">⚠️ Failure Report</h2>
|
||||
<p>The following services/containers failed even after restart attempts:</p>
|
||||
<hr>
|
||||
"""
|
||||
|
||||
for name, logs in failures.items():
|
||||
html += f"""
|
||||
<div style="margin-bottom: 20px; padding: 10px; background-color: #fff3cd; border-left: 5px solid #dc3545;">
|
||||
<h3 style="margin: 0; color: #721c24;">❌ {name} Failed</h3>
|
||||
<p><b>Last 20 log lines:</b></p>
|
||||
<pre style="background-color: #f1f1f1; padding: 10px; border-radius: 5px; max-height: 300px; overflow-y: auto; font-size: 12px; color: #212529;">{logs}</pre>
|
||||
</div>
|
||||
"""
|
||||
|
||||
html += """
|
||||
<hr>
|
||||
<p style="color: #6c757d;">This is an automated alert. Please check the server immediately.</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
msg.attach(MIMEText(html, "html"))
|
||||
|
||||
with smtplib.SMTP(smtp_server, smtp_port) as server:
|
||||
server.starttls()
|
||||
server.login(smtp_user, smtp_password)
|
||||
server.sendmail(sender_email, receiver_email, msg.as_string())
|
||||
|
||||
if __name__ == "__main__":
|
||||
failures = {}
|
||||
print("inside __main__")
|
||||
for service in services:
|
||||
print("looping services: " + service)
|
||||
ok, logs = check_service(service)
|
||||
print(ok)
|
||||
print(logs)
|
||||
if not ok:
|
||||
failures[service] = logs
|
||||
|
||||
for container in containers:
|
||||
ok, logs = check_container(container)
|
||||
print("looping containers: " + container)
|
||||
print(ok)
|
||||
print(logs)
|
||||
if not ok:
|
||||
failures[f"Docker: {container}"] = logs
|
||||
print(failures)
|
||||
send_email(failures)
|
||||
Loading…
x
Reference in New Issue
Block a user