Index: /branches/amp_4_0/amp.spec
===================================================================
--- /branches/amp_4_0/amp.spec	(revision 2905)
+++ /branches/amp_4_0/amp.spec	(working copy)
@@ -226,6 +226,7 @@
 install -Dm 0755 scripts/stripfile %{buildroot}/ca/conf/stripfile
 install -Dm 0755 scripts/name_services.pl %{buildroot}/ca/bin/name_services.pl
 install -Dm 0755 scripts/cassh_init.sh %{buildroot}/ca/bin/cassh_init.sh
+install -Dm 0755 scripts/amp_sync_postfix_smtp.sh %{buildroot}/ca/bin/amp_sync_postfix_smtp.sh
 install -Dm 0755 tools/arrayfirstboot %{buildroot}/ca/etc/
 install -Dm 0755 tools/click_pub_cert.pem %{buildroot}/ca/etc/
 install -Dm 0755 tools/words %{buildroot}/ca/etc/
@@ -265,6 +266,7 @@
 install -Dm 0755 scripts/check_webui_root_user.py %{buildroot}/ca/bin/check_webui_root_user.py
 install -Dm 0755 scripts/check_crontab_add.py %{buildroot}/ca/bin/check_crontab_add.py
 install -Dm 0755 scripts/clean_oper_log.py %{buildroot}/ca/bin/clean_oper_log.py
+install -Dm 0755 scripts/amp_sync_postfix_smtp.sh %{buildroot}/ca/bin/amp_sync_postfix_smtp.sh
 mkdir -p %{buildroot}/ca/webui/htdocs/new/src/hive/media/docs
 
 %files
@@ -309,6 +311,7 @@
 %attr (755,root,root)/ca/bin/connectustack.sh
 %attr (755,root,root)/ca/bin/reloadmacpool.py
 %attr (755,root,root)/ca/bin/cassh_init.sh
+%attr (755,root,root)/ca/bin/amp_sync_postfix_smtp.sh
 %attr (755,root,root)/ca/bin/webui_agent
 %attr (755,root,root)/ca/bin/webui_monitor
 %attr (644,root,root)/ca/etc/arrayfirstboot
@@ -349,6 +352,7 @@
 %attr (755,root,root)/ca/bin/check_webui_root_user.py
 %attr (755,root,root)/ca/bin/check_crontab_add.py
 %attr (755,root,root)/ca/bin/clean_oper_log.py
+%attr (755,root,root)/ca/bin/amp_sync_postfix_smtp.sh
 
 %define __debug_install_post   \
    %{_rpmconfigdir}/find-debuginfo.sh %{?_find_debuginfo_opts} "%{_builddir}/%{?buildsubdir}"\
Index: /branches/amp_4_0/platform/config/init_db.sql
===================================================================
--- /branches/amp_4_0/platform/config/init_db.sql	(revision 2905)
+++ /branches/amp_4_0/platform/config/init_db.sql	(working copy)
@@ -371,18 +371,24 @@
 CREATE TABLE IF NOT EXISTS settings
 (
     id SERIAL PRIMARY KEY,
-    attribute_name varchar(64) NOT NULL,
-    attribute_value TEXT          DEFAULT NULL,
-    time TIMESTAMP   NOT NULL DEFAULT CURRENT_TIMESTAMP
+    attribute_name VARCHAR(64) NOT NULL,
+    attribute_value JSONB,
+    time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+
+    CONSTRAINT uniq_settings_attribute_name
+        UNIQUE (attribute_name)
 );
 
 CREATE TABLE IF NOT EXISTS notification
 (
-    id serial  PRIMARY KEY,
-    name varchar(64) NOT NULL,
-    type varchar(64) NOT NULL,
-    setting varchar(64)          DEFAULT NULL,
-    time        TIMESTAMP   NOT NULL DEFAULT CURRENT_TIMESTAMP
+    id SERIAL PRIMARY KEY,
+    name VARCHAR(64) NOT NULL,
+    type VARCHAR(64) NOT NULL,
+    setting JSONB NOT NULL,
+    time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+
+    CONSTRAINT uniq_notification_name_type
+        UNIQUE (name, type)
 );
 
 -- Create a adc_vs_ssl_info table
\ No newline at end of file
Index: /branches/amp_4_0/platform/tools/scripts/install_postfix.sh
===================================================================
--- /branches/amp_4_0/platform/tools/scripts/install_postfix.sh	(revision 2905)
+++ /branches/amp_4_0/platform/tools/scripts/install_postfix.sh	(working copy)
@@ -1,85 +1,136 @@
 #!/bin/bash
+set -euo pipefail
 
-# === SETUP LOGGING ===
+# ============================================================
+# CONFIG
+# ============================================================
 LOG_FILE="/var/log/install_postfix.log"
-mkdir -p "$(dirname "$LOG_FILE")"
-exec >> "$LOG_FILE" 2>&1
-
-# === DATABASE CONNECTION CONFIG ===
 DB_NAME="cm"
 DB_USER="amp_admin"
 DB_HOST="127.0.0.1"
 DB_PORT="5432"
 
-# === Extract SMTP settings from SETTINGS table ===
-SMTP_JSON=$(psql -qtA -U "$DB_USER" -d "$DB_NAME" -h "$DB_HOST" -p "$DB_PORT" \
-  -c "SELECT attribute_value FROM SETTINGS WHERE attribute_name = 'smtp'" | tr -d '[:space:]')
+POSTFIX_DIR="/etc/postfix"
+SASL_PASSWD="$POSTFIX_DIR/sasl_passwd"
+GENERIC_MAP="$POSTFIX_DIR/generic"
 
-# === Extract EMAIL_TO from NOTIFICATION table ===
-EMAIL_TO_JSON=$(psql -qtA -U "$DB_USER" -d "$DB_NAME" -h "$DB_HOST" -p "$DB_PORT" \
-  -c "SELECT setting FROM NOTIFICATION WHERE type = 'email' LIMIT 1" | tr -d '[:space:]')
+# ============================================================
+# LOGGING
+# ============================================================
+mkdir -p "$(dirname "$LOG_FILE")"
+exec >>"$LOG_FILE" 2>&1
 
-# === Parse using jq ===
-SMTP_SERVER=$(echo "$SMTP_JSON" | jq -r '.Host')
-SMTP_PORT=$(echo "$SMTP_JSON" | jq -r '.Port')
-EMAIL_FROM=$(echo "$SMTP_JSON" | jq -r '.from_address')
-EMAIL_USER=$(echo "$SMTP_JSON" | jq -r '.User')
-EMAIL_PASS=$(echo "$SMTP_JSON" | jq -r '.Password')
+log() {
+    echo "$(date '+%F %T') [postfix-setup] $*"
+}
 
+fail() {
+    log "ERROR: $*"
+    exit 1
+}
 
-# === Function: Install if missing ===
+log "Starting Postfix SMTP configuration"
+
+# ============================================================
+# DEPENDENCIES
+# ============================================================
 install_if_missing() {
-    local pkg="$1"
-    if ! rpm -q "$pkg" &>/dev/null; then
-        echo "Installing missing package: $pkg"
-        dnf install -y "$pkg"
-    else
-        echo "Package already installed: $pkg"
-    fi
+    rpm -q "$1" &>/dev/null || dnf install -y "$1"
 }
 
-# === Install Required Packages ===
-echo "Checking and installing required packages..."
+log "Installing required packages"
 install_if_missing postfix
-install_if_missing s-nail
 install_if_missing cyrus-sasl
 install_if_missing cyrus-sasl-plain
-install_if_missing sysstat
+install_if_missing s-nail
+install_if_missing jq
 
-# === Enable and Start Postfix ===
-echo "Enabling and starting Postfix..."
+# ============================================================
+# READ SMTP SETTINGS FROM DB
+# ============================================================
+log "Fetching SMTP settings from database"
+
+SMTP_JSON=$(psql -qtA -U "$DB_USER" -d "$DB_NAME" -h "$DB_HOST" -p "$DB_PORT" \
+    -c "SELECT attribute_value FROM settings WHERE attribute_name='smtp'" \
+    | tr -d '\n')
+
+[[ -z "$SMTP_JSON" ]] && fail "SMTP settings not found in DB"
+
+SMTP_ENABLED=$(echo "$SMTP_JSON" | jq -r '.Enabled // false')
+[[ "$SMTP_ENABLED" != "true" ]] && {
+    log "SMTP is disabled in DB — exiting"
+    exit 0
+}
+
+SMTP_HOST=$(echo "$SMTP_JSON" | jq -r '.Host')
+SMTP_PORT=$(echo "$SMTP_JSON" | jq -r '.Port')
+SMTP_USER=$(echo "$SMTP_JSON" | jq -r '.User // empty')
+SMTP_PASS=$(echo "$SMTP_JSON" | jq -r '.Password // empty')
+SMTP_FROM=$(echo "$SMTP_JSON" | jq -r '.from_address')
+
+[[ -z "$SMTP_HOST" || -z "$SMTP_PORT" || -z "$SMTP_FROM" ]] \
+    && fail "Invalid SMTP configuration"
+
+# ============================================================
+# ENABLE & START POSTFIX
+# ============================================================
+log "Enabling Postfix service"
 systemctl enable --now postfix
 
-# Generate mapping database
-postmap /etc/postfix/generic
+# ============================================================
+# BASE POSTFIX CONFIG (SAFE DEFAULTS)
+# ============================================================
+log "Applying base Postfix configuration"
 
-# === Configure Postfix ===
-echo "Configuring Postfix for SMTP relay..."
-postconf -e "relayhost = [$SMTP_SERVER]:$SMTP_PORT"
-postconf -e "smtp_use_tls = yes"
-postconf -e "smtp_sasl_auth_enable = yes"
-postconf -e "smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd"
-postconf -e "smtp_sasl_security_options = noanonymous"
-postconf -e "smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt"
-postconf -e "myhostname = $(hostname)"
+postconf -e "relayhost = [$SMTP_HOST]:$SMTP_PORT"
 postconf -e "inet_interfaces = loopback-only"
+postconf -e "inet_protocols = ipv4"
 postconf -e "mydestination ="
-postconf -e "smtp_generic_maps = hash:/etc/postfix/generic"
+postconf -e "smtp_use_tls = yes"
+postconf -e "smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt"
+postconf -e "smtp_tls_security_level = encrypt"
+postconf -e "smtp_tls_loglevel = 1"
 
-# === Create SASL Password File ===
-echo "Creating /etc/postfix/sasl_passwd..."
-mkdir -p /etc/postfix
-cat <<EOF > /etc/postfix/sasl_passwd
-[$SMTP_SERVER]:$SMTP_PORT $EMAIL_USER:$EMAIL_PASS
+# ============================================================
+# SENDER REWRITE (GENERIC MAP)
+# ============================================================
+log "Configuring sender rewrite"
+
+cat <<EOF >"$GENERIC_MAP"
+root@$(hostname -f)        $SMTP_FROM
+root@localhost             $SMTP_FROM
+root@localhost.localdomain $SMTP_FROM
+MAILER-DAEMON@$(hostname -f) $SMTP_FROM
 EOF
 
-chmod 600 /etc/postfix/sasl_passwd
-postmap /etc/postfix/sasl_passwd
+chmod 600 "$GENERIC_MAP"
+postmap "$GENERIC_MAP"
 
-# === Restart Postfix ===
-echo "Restarting Postfix..."
+postconf -e "smtp_generic_maps = hash:$GENERIC_MAP"
+
+# ============================================================
+# SMTP AUTH (OPTIONAL)
+# ============================================================
+
+cat <<EOF >"$SASL_PASSWD"
+[$SMTP_HOST]:$SMTP_PORT $SMTP_USER:$SMTP_PASS
+EOF
+
+chmod 600 "$SASL_PASSWD"
+postmap "$SASL_PASSWD"
+
+postconf -e "smtp_sasl_auth_enable = yes"
+postconf -e "smtp_sasl_password_maps = hash:$SASL_PASSWD"
+postconf -e "smtp_sasl_security_options = noanonymous"
+
+# ============================================================
+# RESTART POSTFIX
+# ============================================================
+log "Restarting Postfix"
 systemctl restart postfix
 
+log "Postfix SMTP configuration completed successfully"
+
 chmod +x send_cpu_memory_stats.sh
 
 # === Add Cron Job ===
Index: /branches/amp_4_0/scripts/amp_sync_postfix_smtp.sh
===================================================================
--- /branches/amp_4_0/scripts/amp_sync_postfix_smtp.sh	(nonexistent)
+++ /branches/amp_4_0/scripts/amp_sync_postfix_smtp.sh	(working copy)
@@ -0,0 +1,92 @@
+#!/bin/bash
+set -euo pipefail
+
+LOG="/var/log/amp_sync_postfix_smtp.log"
+LOCK_FILE="/var/run/amp_postfix_sync.lock"
+
+log() {
+    echo "$(date '+%F %T') $1" | tee -a "$LOG"
+}
+
+# --- locking ---
+exec 9>"$LOCK_FILE" || exit 1
+if ! flock -n 9; then
+    log "[INFO] Another postfix sync already running, exiting"
+    exit 0
+fi
+
+DB="cm"
+DB_USER="amp_admin"
+DB_HOST="127.0.0.1"
+DB_PORT="5432"
+
+log "[INFO] Starting AMP Postfix SMTP sync"
+
+# --- Fetch SMTP JSON ---
+SMTP_JSON=$(psql -qtA \
+  -U "$DB_USER" \
+  -d "$DB" \
+  -h "$DB_HOST" \
+  -p "$DB_PORT" \
+  -c "SELECT attribute_value FROM settings WHERE attribute_name='smtp'" \
+  || true)
+
+if [[ -z "$SMTP_JSON" || "$SMTP_JSON" == "null" ]]; then
+    log "[INFO] SMTP settings not configured. Skipping Postfix sync."
+    exit 0
+fi
+
+# --- Parse fields ---
+HOST=$(jq -r '.Host // empty' <<<"$SMTP_JSON")
+PORT=$(jq -r '.Port // empty' <<<"$SMTP_JSON")
+USER=$(jq -r '.User // empty' <<<"$SMTP_JSON")
+PASS=$(jq -r '.Password // empty' <<<"$SMTP_JSON")
+FROM=$(jq -r '.from_address // empty' <<<"$SMTP_JSON")
+
+if [[ -z "$HOST" || -z "$PORT" || -z "$USER" || -z "$PASS" || -z "$FROM" ]]; then
+    log "[WARN] Incomplete SMTP settings. Skipping Postfix sync."
+    exit 0
+fi
+
+log "[INFO] Applying SMTP relay config for $HOST:$PORT"
+
+# --- Postfix core config ---
+postconf -e "relayhost = [$HOST]:$PORT"
+postconf -e "smtp_use_tls = yes"
+postconf -e "smtp_sasl_auth_enable = yes"
+postconf -e "smtp_sasl_security_options = noanonymous"
+postconf -e "smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd"
+postconf -e "smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt"
+postconf -e "inet_protocols = ipv4"
+
+# --- SASL credentials ---
+cat >/etc/postfix/sasl_passwd <<EOF
+[$HOST]:$PORT $USER:$PASS
+EOF
+
+chmod 600 /etc/postfix/sasl_passwd
+postmap /etc/postfix/sasl_passwd
+
+# --- Sender rewrite ---
+GENERIC="/etc/postfix/generic"
+HOSTNAME_FQDN=$(hostname -f 2>/dev/null || hostname)
+
+cat >"$GENERIC" <<EOF
+root@$HOSTNAME_FQDN        $FROM
+root@localhost            $FROM
+root@localhost.localdomain $FROM
+MAILER-DAEMON@$HOSTNAME_FQDN $FROM
+EOF
+
+chmod 644 "$GENERIC"
+postmap "$GENERIC"
+
+postconf -e "smtp_generic_maps = hash:/etc/postfix/generic"
+
+# --- reload safely ---
+if ! systemctl reload postfix; then
+    log "[WARN] Reload failed, restarting postfix"
+    systemctl restart postfix
+fi
+
+log "[INFO] SMTP sync completed successfully"
\ No newline at end of file
Index: /branches/amp_4_0/scripts/avxapps_startup.sh
===================================================================
--- /branches/amp_4_0/scripts/avxapps_startup.sh	(revision 2905)
+++ /branches/amp_4_0/scripts/avxapps_startup.sh	(working copy)
@@ -223,3 +223,6 @@
 # Import kibana dashboard during the startup
 /bin/bash /ca/bin/import_kibana_dashboard.sh
 
+# Make Postfix related changes during startup
+/bin/bash /ca/bin/amp_sync_postfix_smtp.sh
+
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/djproject/urls.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/djproject/urls.py	(revision 2905)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/djproject/urls.py	(working copy)
@@ -1,6 +1,7 @@
 from django.urls import re_path
 
-from hive.controller.apv_services_metrics import handle_get_top_apv_virtual_services_metrics, handle_get_top_apv_real_services_metrics, handle_get_top_llb_metrics
+from hive.controller.apv_services_metrics import handle_get_top_apv_virtual_services_metrics, \
+    handle_get_top_apv_real_services_metrics, handle_get_top_llb_metrics
 from hive.controller.devices_metrics import handle_get_top_devices_metrics, handle_get_devices_network_metrics
 from hive.router import *
 from hive.session import login_handler, logout_handler, register_complete, app_login_handler, app_logout_handler
@@ -12,7 +13,8 @@
 from hive.utils import hive_webpipe_handler, hive_webpipe_write_handler
 from hive.node import reload_app_node
 from hive.session import current_app
-from hive.composer import KibanaProxyView, elastic_proxy, reporting_downloading_handler, reporting_logo_handler, composer_config, composer_status, composer_query, composer_proxy
+from hive.composer import KibanaProxyView, elastic_proxy, reporting_downloading_handler, reporting_logo_handler, \
+    composer_config, composer_status, composer_query, composer_proxy
 from hive.storage import storage_mangement
 from hive.log_location import handle_log_location_app
 from hive.controller.device_metrics import handle_device_metrics_req
@@ -27,9 +29,10 @@
 from hive.an_opensearch import opensearch_proxy, get_opensearch_sso_token
 from hive.controller.system_metrics import handle_get_latest_system_metrics, handle_get_historical_system_metrics
 from hive.controller.generic_controller import handle_service_query_req
+from hive.controller.notification_controller import handle_notification_req
 
 js_info_dict = {
-    #'packages': ('your.app.package',),
+    # 'packages': ('your.app.package',),
 }
 
 urlpatterns = [
@@ -83,6 +86,7 @@
     re_path(r'^log/(?P<app>\w+)$', handle_log_location_app),
     re_path(r'^backup/(?P<path>.*)$', handle_backup_req),
     re_path(r'^restore/(?P<path>.*)$', handle_restore_req),
+    re_path(r'^notification/(?P<path>.*)$', handle_notification_req),
     re_path(r'^real_service$', real_service),
     re_path(r'^rs_block$', rs_block),
     re_path(r'^rs_block_import$', rs_block_import),
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/controller/notification_controller.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/controller/notification_controller.py	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/controller/notification_controller.py	(working copy)
@@ -0,0 +1,121 @@
+import json
+from hive.services.notification_service import NotificationService
+from hive.model.smtp_settings import SMTPSettings
+from django.http import JsonResponse
+from hive.custom_exceptions import generic_exception as ge
+
+from cm.lib.libbasic_operation import oper_log
+from hive.utils import andebug
+
+
+def handle_notification_req(request, path=None):
+    try:
+        if request.method == 'POST':
+            if path == 'smtp_setting':
+                return save_smtp_setting(request)
+            elif path == 'mail':
+                return save_email_notification(request)
+            else:
+                return JsonResponse({
+                    'error': 400,
+                    'message': "Invalid notification path"
+                }, status=400)
+        elif request.method == 'GET':
+            if path == 'smtp_setting':
+                return get_smtp_setting()
+            elif path == 'mail':
+                return get_email_notifications()
+            else:
+                return JsonResponse(
+                    {"error": "Invalid notification path"},
+                    status=400
+                )
+        else:
+            return JsonResponse({
+                'error': 400,
+                'message': "Invalid HTTP method"
+            }, status=400)
+
+    except ge.GenericError as e:
+        oper_log('error', 'system', str(e))
+        return ge.handle_exception(e)
+    except Exception as e:
+        msg = f'Exception while processing notification request., details: {str(e)}'
+        oper_log('error', 'system', msg)
+        raise ge.GenericError(500, msg)
+
+
+def save_smtp_setting(request):
+    body = json.loads(request.body)
+
+    required = ["host", "port", "user", "password", "from_address"]
+    for field in required:
+        if field not in body:
+            return JsonResponse(
+                {"error": f"{field} is required"},
+                status=400
+            )
+
+    smtp = SMTPSettings(
+        enabled=body.get("enabled", True),
+        host=body["host"],
+        port=body["port"],
+        user=body["user"],
+        password=body["password"],
+        from_address=body["from_address"],
+        from_name=body.get("from_name", "")
+    )
+
+    service = NotificationService()
+    service.save_smtp(smtp)
+
+    return JsonResponse(
+        {"status": "SMTP settings saved"},
+        status=200
+    )
+
+
+def save_email_notification(request):
+    body = json.loads(request.body)
+
+    addresses = body.get("addresses")
+    if not isinstance(addresses, list):
+        return JsonResponse(
+            {"error": "addresses must be a list"},
+            status=400
+        )
+
+    name = body.get("name", "default")
+    n_type = body.get("type", "email")
+
+    service = NotificationService()
+    service.save_email_notification(
+        name, n_type, addresses
+    )
+
+    return JsonResponse(
+        {"status": "Notification saved"},
+        status=200
+    )
+
+
+def get_smtp_setting():
+    service = NotificationService()
+    data = service.get_smtp()
+
+    return JsonResponse(
+        data,
+        safe=False,
+        status=200
+    )
+
+
+def get_email_notifications():
+    service = NotificationService()
+    data = service.get_email_notifications()
+
+    return JsonResponse(
+        data,
+        safe=False,
+        status=200
+    )
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/db/notification_repository.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/db/notification_repository.py	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/db/notification_repository.py	(working copy)
@@ -0,0 +1,130 @@
+import json
+from hive.db.db_client import DBClient
+from hive.utils import andebug
+
+
+class NotificationRepository:
+
+    def insert_setting(self, name, value_json):
+        query = """
+            INSERT INTO settings (attribute_name, attribute_value)
+            VALUES (%s, %s)
+            ON CONFLICT (attribute_name)
+            DO UPDATE SET
+                attribute_value = EXCLUDED.attribute_value,
+                time = CURRENT_TIMESTAMP
+        """
+
+        req_dict = {
+            "query": query,
+            "params": [name, json.dumps(value_json)]
+        }
+
+        DBClient.execute_query(req_dict, "postgres")
+
+    def insert_notification(self, name, ntype, setting_json):
+        query = """
+            INSERT INTO notification (name, type, setting)
+            VALUES (%s, %s, %s)
+            ON CONFLICT (name, type)
+            DO UPDATE SET
+                setting = EXCLUDED.setting,
+                time = CURRENT_TIMESTAMP
+        """
+
+        req_dict = {
+            "query": query,
+            "params": [name, ntype, json.dumps(setting_json)]
+        }
+
+        DBClient.execute_query(req_dict, "postgres")
+
+    def get_setting(self, name):
+        query = """
+            SELECT attribute_value
+            FROM settings
+            WHERE attribute_name = %s
+        """
+
+        req_dict = {
+            "query": query,
+            "params": [name]
+        }
+
+        res = DBClient.execute_query(req_dict, "postgres")
+        if res.get("status") != 200:
+            raise Exception(res.get("data"))
+
+        data = res.get("data", [])
+
+        if not data:
+            return {}
+
+        value = data[0].get("attribute_value")
+
+        # psycopg2 may return JSONB as str or dict depending on config
+        if isinstance(value, str):
+            return json.loads(value)
+
+        return value
+
+    def get_notifications_by_type(self, ntype):
+        query = """
+            SELECT name, type, setting, time
+            FROM notification
+            WHERE type = %s
+            ORDER BY time DESC
+        """
+
+        req_dict = {
+            "query": query,
+            "params": [ntype]
+        }
+
+        res = DBClient.execute_query(req_dict, db="postgres")
+
+        if res.get("status") != 200:
+            raise Exception(res.get("data"))
+
+        data = res.get("data", [])
+
+        # Ensure JSONB is returned as Python dict
+        for row in data:
+            setting = row.get("setting")
+            if isinstance(setting, str):
+                row["setting"] = json.loads(setting)
+
+        return data
+
+    def get_notification_addr_by_name(self, name):
+        query = """
+            SELECT setting
+            FROM notification
+            WHERE name = %s
+            LIMIT 1
+        """
+
+        req = {
+            "query": query,
+            "params": [name]
+        }
+
+        res = DBClient.execute_query(req, db="postgres")
+
+        if res.get("status") != 200:
+            raise Exception(f"DB error while fetching notification '{name}': {res.get('data')}")
+
+        rows = res.get("data")
+        if not rows:
+            return None  # Notification not configured
+
+        setting = rows[0].get("setting")
+
+        # Normalize JSONB → dict (psycopg2 may return str or dict)
+        if isinstance(setting, str):
+            try:
+                setting = json.loads(setting)
+            except json.JSONDecodeError:
+                raise Exception(f"Invalid JSON in notification setting for '{name}'")
+
+        return setting
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/model/smtp_settings.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/model/smtp_settings.py	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/model/smtp_settings.py	(working copy)
@@ -0,0 +1,21 @@
+class SMTPSettings:
+    def __init__(self, enabled, host, port, user, password,
+                 from_address, from_name="", cert_file="", key_file=""):
+        self.enabled = enabled
+        self.host = host
+        self.port = port
+        self.user = user
+        self.password = password
+        self.from_address = from_address
+        self.from_name = from_name
+
+    def to_json(self):
+        return {
+            "Enabled": self.enabled,
+            "Host": self.host,
+            "Port": self.port,
+            "User": self.user,
+            "Password": self.password,
+            "from_address": self.from_address,
+            "from_name": self.from_name
+        }
\ No newline at end of file
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/report/generate_report.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/report/generate_report.py	(revision 2905)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/report/generate_report.py	(working copy)
@@ -1,6 +1,10 @@
 import json
 import os
 import time
+import smtplib
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
+from email.mime.application import MIMEApplication
 from django.http import JsonResponse, StreamingHttpResponse
 from hive.report.report_utils import get_dynamic_interval, to_epoch_ms, convert_relative_time, resolve_time_ranges
 from hive.report.report_data_service import get_llb_detailed_data, get_link_summary_data, \
@@ -10,6 +14,7 @@
 from hive.custom_exceptions import generic_exception as ge
 from hive.report.report_queries import ReportDB
 from hive.report.generate_pdf_report import Report
+from hive.services.notification_service import NotificationService
 from hive.utils import andebug
 
 REPORT_FILE_PATH = "/ca/webui/htdocs/new/src/hive/media/docs/"
@@ -290,6 +295,7 @@
     to_time = report.get("to_time")
     sub_type = report.get("subject_type")
     time_interval = get_dynamic_interval(from_time, to_time)
+    send_to = report.get("send_to")
 
     if sub_type == "service_status":
         sub_name = report.get("subject_name", "")
@@ -319,6 +325,33 @@
     ReportDB.update_report_log(report_id, status, report_name, file_size)
     ReportDB.update_report_status(status, report_id)
     if status:
+        if send_to:
+            try:
+                notif = NotificationService()
+                recipients = notif.get_email_recipients(send_to)
+                if not recipients:
+                    oper_log("warn", "report",
+                             f"No email recipients resolved for send_to={send_to}")
+
+                smtp_cfg = notif.get_smtp()
+
+                if not smtp_cfg:
+                    raise Exception("SMTP not configured")
+
+                send_email_with_attachment(
+                    from_address=smtp_cfg["from_address"],
+                    to_addresses=recipients,
+                    subject=f"Report Generated: {report_name}",
+                    body=f"The report '{report_name}' has been generated successfully.",
+                    attachment_path=file_path
+                )
+
+                oper_log("info", "report",
+                         f"Report {report_id} emailed to {len(recipients)} recipients")
+
+            except Exception as e:
+                oper_log("error", "report",
+                         f"Email send failed for report {report_id}: {str(e)}")
         return JsonResponse(
             {
                 "message": "Report generated successfully",
@@ -333,6 +366,48 @@
         return JsonResponse({"error": "Report generation failed"}, status=500)
 
 
+def send_email_with_attachment(
+    from_address,
+    to_addresses,
+    subject,
+    body,
+    attachment_path=None
+):
+    # Normalize recipients
+    if isinstance(to_addresses, dict):
+        recipient_list = to_addresses.get("addresses", [])
+    elif isinstance(to_addresses, (list, tuple)):
+        recipient_list = list(to_addresses)
+    else:
+        raise ValueError(f"Invalid to_addresses type: {type(to_addresses)}")
+
+    if not recipient_list:
+        raise ValueError("No valid recipient addresses found")
+
+    msg = MIMEMultipart()
+    msg["From"] = from_address
+    msg["To"] = ", ".join(recipient_list)
+    msg["Subject"] = subject
+
+    msg.attach(MIMEText(body, "plain"))
+
+    if attachment_path and os.path.isfile(attachment_path):
+        with open(attachment_path, "rb") as f:
+            part = MIMEApplication(f.read(), Name=os.path.basename(attachment_path))
+            part["Content-Disposition"] = (
+                f'attachment; filename="{os.path.basename(attachment_path)}"'
+            )
+            msg.attach(part)
+
+    with smtplib.SMTP("localhost", 25, timeout=30) as server:
+        result = server.sendmail(from_address, recipient_list, msg.as_string())
+
+        # sendmail returns dict of failed recipients
+        if result:
+            oper_log("error", "report",
+                     f"SMTP accepted mail but failed for recipients: {result}")
+
+
 def generate_llb_report(report, from_time, to_time, time_interval):
     data_dict = get_llb_detailed_data(from_time, to_time, None, time_interval)
     data_summary_dict = get_link_summary_data(from_time, to_time)
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/report/report_data_service.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/report/report_data_service.py	(revision 2905)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/report/report_data_service.py	(working copy)
@@ -315,6 +315,7 @@
     except Exception as e:
         return JsonResponse({"error": f"Error while fetching Device Detailed data: {str(e)}"}, status=500)
 
+
 def update_report_service(report_id, update_payload):
     """
     Fetch existing report and update only provided fields.
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/services/notification_service.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/services/notification_service.py	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/services/notification_service.py	(working copy)
@@ -0,0 +1,47 @@
+from hive.model.smtp_settings import SMTPSettings
+from hive.db.notification_repository import NotificationRepository
+from hive.utils import andebug
+import json
+import subprocess
+
+
+class NotificationService:
+
+    def __init__(self):
+        self.notification_repo = NotificationRepository()
+
+    def save_smtp(self, smtp_settings: SMTPSettings):
+        smtp_json = smtp_settings.to_json()
+        self.notification_repo.insert_setting("smtp", smtp_json)
+
+        # update the postfix configuration
+        with open("/var/log/amp_postfix_sync.log", "a") as log:
+            subprocess.Popen(
+                ["/bin/bash", "/ca/bin/amp_sync_postfix_smtp.sh"],
+                stdout=log,
+                stderr=log,
+                start_new_session=True
+            )
+
+    def save_email_notification(self, name, n_type, addresses):
+        if not addresses:
+            raise ValueError("Email address list cannot be empty")
+
+        notification_json = {
+            "addresses": addresses
+        }
+
+        self.notification_repo.insert_notification(
+            name=name,
+            ntype=n_type,
+            setting_json=notification_json
+        )
+
+    def get_smtp(self):
+        return self.notification_repo.get_setting("smtp")
+
+    def get_email_notifications(self):
+        return self.notification_repo.get_notifications_by_type("email")
+
+    def get_email_recipients(self, name):
+        return self.notification_repo.get_notification_addr_by_name(name)
