feat(smtp-relay): Add unified SMTP relay configuration
- New secubox-app-smtp-relay package with centralized SMTP config - Shared library with send_mail(), send_html_mail(), send_text_mail() - CLI: smtp-relayctl with status/test/send/configure/admin commands - RPCD: 5 methods for LuCI integration - LuCI settings page with mode selection and test button - Modes: external (SMTP server), local (auto-detect mailserver), direct - Migrated reporter and bandwidth-manager to use shared library - Backwards-compatible fallback to legacy per-app config Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
ccccd3d93b
commit
a345c16425
@ -5270,3 +5270,15 @@ git checkout HEAD -- index.html
|
||||
- 6 new RPCD methods: get_tuning, set_tuning, whitelist_add, whitelist_remove, whitelist_list, reset_reputation
|
||||
- UCi config updated with scoring weights, sensitivity, whitelist, decay options
|
||||
- Enables fine-tuning of auto-ban sensitivity for production traffic
|
||||
|
||||
- **Unified SMTP Relay Configuration (2026-03-16)**
|
||||
- New `secubox-app-smtp-relay` package: centralized SMTP config for all SecuBox apps
|
||||
- Shared library with `send_mail()`, `send_html_mail()`, `send_text_mail()` functions
|
||||
- CLI tool: `smtp-relayctl status|test|send|configure|admin|enable|disable`
|
||||
- RPCD backend with 5 methods: get_status, get_config, test_email, send_email, detect_local
|
||||
- LuCI settings page with mode selection, provider presets, connection test
|
||||
- Three modes: external (SMTP server), local (auto-detect mailserver), direct (MTA)
|
||||
- Provider presets: Gmail, SendGrid, Mailgun, Amazon SES, Mailjet
|
||||
- Migrated secubox-reporter and bandwidth-manager to use shared library
|
||||
- Backwards-compatible fallback to legacy per-app SMTP settings
|
||||
- Eliminates duplicated SMTP configuration across SecuBox apps
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Work In Progress (Claude)
|
||||
|
||||
_Last updated: 2026-03-16 (WAF Auto-Ban Tuning)_
|
||||
_Last updated: 2026-03-16 (Unified SMTP Relay)_
|
||||
|
||||
> **Architecture Reference**: SecuBox Fanzine v3 — Les 4 Couches
|
||||
|
||||
@ -10,6 +10,17 @@ _Last updated: 2026-03-16 (WAF Auto-Ban Tuning)_
|
||||
|
||||
### 2026-03-16
|
||||
|
||||
- **Unified SMTP Relay Configuration (Complete)**
|
||||
- New `secubox-app-smtp-relay` package with centralized SMTP config
|
||||
- Shared library `/usr/lib/secubox/mail/smtp-relay.sh` with `send_mail()` function
|
||||
- CLI: `smtp-relayctl status|test|send|configure|admin|enable|disable`
|
||||
- RPCD: get_status, get_config, test_email, send_email, detect_local
|
||||
- LuCI settings page with mode selection, provider config, test button
|
||||
- Modes: external (Gmail, SendGrid, etc.), local (auto-detect mailserver), direct
|
||||
- Migrated `secubox-reporter` and `bandwidth-manager` to use shared library
|
||||
- Backwards-compatible fallback to legacy per-app SMTP settings
|
||||
- Eliminates duplicated SMTP configuration across SecuBox apps
|
||||
|
||||
- **WAF Auto-Ban Tuning System (Complete)**
|
||||
- Configurable scoring weights via UCI `scoring` section
|
||||
- Sensitivity presets: low (0.7x), medium (1.0x), high (1.3x), custom
|
||||
@ -672,7 +683,7 @@ All core features complete. Optional polish tasks remain.
|
||||
|
||||
### Backlog
|
||||
|
||||
- SSMTP / mail host / MX record management (v2)
|
||||
- Advanced mail features: webmail integration, DKIM signing, multiple recipients (v2)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -27,10 +27,33 @@ get_alert_setting() {
|
||||
echo "$value"
|
||||
}
|
||||
|
||||
# Check if centralized SMTP relay is available and enabled
|
||||
_use_smtp_relay() {
|
||||
[ -f /usr/lib/secubox/mail/smtp-relay.sh ] || return 1
|
||||
local enabled
|
||||
enabled=$(uci -q get smtp-relay.main.enabled)
|
||||
[ "$enabled" = "1" ]
|
||||
}
|
||||
|
||||
# Send email notification
|
||||
send_email() {
|
||||
local subject="$1"
|
||||
local body="$2"
|
||||
|
||||
# Use centralized SMTP relay if available
|
||||
if _use_smtp_relay; then
|
||||
. /usr/lib/secubox/mail/smtp-relay.sh
|
||||
local recipient
|
||||
recipient=$(uci -q get smtp-relay.recipients.admin)
|
||||
[ -z "$recipient" ] && {
|
||||
config_load bandwidth
|
||||
config_get recipient email recipient ""
|
||||
}
|
||||
send_text_mail "$recipient" "$subject" "$body"
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Legacy fallback: use per-app config
|
||||
local recipient=""
|
||||
local smtp_server=""
|
||||
local smtp_port=""
|
||||
|
||||
30
package/secubox/luci-app-smtp-relay/Makefile
Normal file
30
package/secubox/luci-app-smtp-relay/Makefile
Normal file
@ -0,0 +1,30 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=LuCI SMTP Relay Configuration
|
||||
LUCI_DEPENDS:=+secubox-app-smtp-relay +luci-base
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
PKG_NAME:=luci-app-smtp-relay
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_MAINTAINER:=SecuBox Team <contact@secubox.io>
|
||||
PKG_LICENSE:=GPL-3.0
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
define Package/luci-app-smtp-relay/install
|
||||
$(INSTALL_DIR) $(1)/usr/libexec/rpcd
|
||||
$(INSTALL_BIN) ./root/usr/libexec/rpcd/luci.smtp-relay $(1)/usr/libexec/rpcd/luci.smtp-relay
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
|
||||
$(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/luci-app-smtp-relay.json $(1)/usr/share/rpcd/acl.d/luci-app-smtp-relay.json
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/share/luci/menu.d
|
||||
$(INSTALL_DATA) ./root/usr/share/luci/menu.d/luci-app-smtp-relay.json $(1)/usr/share/luci/menu.d/luci-app-smtp-relay.json
|
||||
|
||||
$(INSTALL_DIR) $(1)/www/luci-static/resources/view/smtp-relay
|
||||
$(INSTALL_DATA) ./htdocs/luci-static/resources/view/smtp-relay/settings.js $(1)/www/luci-static/resources/view/smtp-relay/settings.js
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,luci-app-smtp-relay))
|
||||
@ -0,0 +1,281 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require form';
|
||||
'require ui';
|
||||
'require uci';
|
||||
'require rpc';
|
||||
|
||||
var callGetStatus = rpc.declare({
|
||||
object: 'luci.smtp-relay',
|
||||
method: 'get_status',
|
||||
expect: {}
|
||||
});
|
||||
|
||||
var callGetConfig = rpc.declare({
|
||||
object: 'luci.smtp-relay',
|
||||
method: 'get_config',
|
||||
expect: {}
|
||||
});
|
||||
|
||||
var callTestEmail = rpc.declare({
|
||||
object: 'luci.smtp-relay',
|
||||
method: 'test_email',
|
||||
params: ['recipient'],
|
||||
expect: {}
|
||||
});
|
||||
|
||||
var callDetectLocal = rpc.declare({
|
||||
object: 'luci.smtp-relay',
|
||||
method: 'detect_local',
|
||||
expect: {}
|
||||
});
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
callGetStatus().catch(function() { return {}; }),
|
||||
callGetConfig().catch(function() { return {}; }),
|
||||
callDetectLocal().catch(function() { return {}; }),
|
||||
uci.load('smtp-relay')
|
||||
]);
|
||||
},
|
||||
|
||||
handleTestEmail: function(ev) {
|
||||
var recipient = document.getElementById('test_recipient').value;
|
||||
var btn = ev.target;
|
||||
var resultDiv = document.getElementById('test_result');
|
||||
|
||||
if (!recipient) {
|
||||
recipient = uci.get('smtp-relay', 'recipients', 'admin') || '';
|
||||
}
|
||||
|
||||
if (!recipient) {
|
||||
ui.addNotification(null, E('p', _('Please enter a recipient email address')), 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
btn.disabled = true;
|
||||
btn.textContent = _('Sending...');
|
||||
resultDiv.innerHTML = '';
|
||||
|
||||
callTestEmail(recipient).then(function(res) {
|
||||
btn.disabled = false;
|
||||
btn.textContent = _('Send Test Email');
|
||||
|
||||
if (res.success) {
|
||||
resultDiv.innerHTML = '<span style="color: #4caf50;">✓ ' + _('Test email sent successfully!') + '</span>';
|
||||
ui.addNotification(null, E('p', _('Test email sent to %s').format(recipient)), 'info');
|
||||
} else {
|
||||
resultDiv.innerHTML = '<span style="color: #f44336;">✗ ' + (res.error || _('Failed to send')) + '</span>';
|
||||
ui.addNotification(null, E('p', res.error || _('Failed to send test email')), 'error');
|
||||
}
|
||||
}).catch(function(err) {
|
||||
btn.disabled = false;
|
||||
btn.textContent = _('Send Test Email');
|
||||
resultDiv.innerHTML = '<span style="color: #f44336;">✗ ' + err.message + '</span>';
|
||||
});
|
||||
},
|
||||
|
||||
render: function(data) {
|
||||
var status = data[0] || {};
|
||||
var config = data[1] || {};
|
||||
var localDetect = data[2] || {};
|
||||
var m, s, o;
|
||||
|
||||
m = new form.Map('smtp-relay', _('SMTP Relay'),
|
||||
_('Centralized outbound email configuration for all SecuBox services. Configure once, use everywhere.'));
|
||||
|
||||
// Status section
|
||||
s = m.section(form.NamedSection, 'main', 'smtp_relay', _('Status'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.DummyValue, '_status', _('Current Status'));
|
||||
o.rawhtml = true;
|
||||
o.cfgvalue = function() {
|
||||
var modeText = {
|
||||
'external': _('External SMTP Server'),
|
||||
'local': _('Local Mailserver'),
|
||||
'direct': _('Direct Delivery')
|
||||
};
|
||||
var statusHtml = '<div style="display: flex; gap: 20px; flex-wrap: wrap;">';
|
||||
|
||||
// Enabled status
|
||||
statusHtml += '<div><strong>' + _('Relay:') + '</strong> ';
|
||||
if (status.enabled) {
|
||||
statusHtml += '<span style="color: #4caf50;">●</span> ' + _('Enabled');
|
||||
} else {
|
||||
statusHtml += '<span style="color: #f44336;">●</span> ' + _('Disabled');
|
||||
}
|
||||
statusHtml += '</div>';
|
||||
|
||||
// Mode
|
||||
statusHtml += '<div><strong>' + _('Mode:') + '</strong> ' + (modeText[status.mode] || status.mode || '-') + '</div>';
|
||||
|
||||
// Server
|
||||
if (status.server) {
|
||||
statusHtml += '<div><strong>' + _('Server:') + '</strong> ' + status.server + ':' + status.port + '</div>';
|
||||
}
|
||||
|
||||
// Transport
|
||||
statusHtml += '<div><strong>' + _('Transport:') + '</strong> ';
|
||||
if (status.msmtp_available) {
|
||||
statusHtml += '<span style="color: #4caf50;">msmtp</span>';
|
||||
} else if (status.sendmail_available) {
|
||||
statusHtml += '<span style="color: #ff9800;">sendmail</span>';
|
||||
} else {
|
||||
statusHtml += '<span style="color: #f44336;">' + _('None') + '</span>';
|
||||
}
|
||||
statusHtml += '</div>';
|
||||
|
||||
// Local mailserver
|
||||
if (localDetect.detected) {
|
||||
statusHtml += '<div><strong>' + _('Local Mail:') + '</strong> ';
|
||||
if (localDetect.responding) {
|
||||
statusHtml += '<span style="color: #4caf50;">● ' + _('Available') + '</span>';
|
||||
} else {
|
||||
statusHtml += '<span style="color: #ff9800;">● ' + _('Not responding') + '</span>';
|
||||
}
|
||||
statusHtml += '</div>';
|
||||
}
|
||||
|
||||
statusHtml += '</div>';
|
||||
return statusHtml;
|
||||
};
|
||||
|
||||
// Main settings
|
||||
s = m.section(form.NamedSection, 'main', 'smtp_relay', _('General Settings'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.Flag, 'enabled', _('Enable SMTP Relay'));
|
||||
o.default = '0';
|
||||
o.rmempty = false;
|
||||
|
||||
o = s.option(form.ListValue, 'mode', _('Relay Mode'));
|
||||
o.value('external', _('External SMTP Server'));
|
||||
o.value('local', _('Local Mailserver'));
|
||||
o.value('direct', _('Direct Delivery (MTA)'));
|
||||
o.default = 'external';
|
||||
o.description = _('External: Use Gmail, SendGrid, etc. Local: Use secubox-app-mailserver. Direct: Send directly (requires port 25).');
|
||||
|
||||
o = s.option(form.Flag, 'auto_detect', _('Auto-detect Local Mailserver'));
|
||||
o.description = _('Automatically use local mailserver if available and responding');
|
||||
o.default = '1';
|
||||
o.depends('mode', 'external');
|
||||
|
||||
// External SMTP section
|
||||
s = m.section(form.NamedSection, 'external', 'external', _('External SMTP Settings'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.ListValue, '_preset', _('Provider Preset'));
|
||||
o.value('', _('-- Custom --'));
|
||||
o.value('gmail', 'Gmail / Google Workspace');
|
||||
o.value('sendgrid', 'SendGrid');
|
||||
o.value('mailgun', 'Mailgun');
|
||||
o.value('ses', 'Amazon SES (us-east-1)');
|
||||
o.value('mailjet', 'Mailjet');
|
||||
o.rmempty = true;
|
||||
o.write = function() {}; // Don't save, just triggers onchange
|
||||
|
||||
o = s.option(form.Value, 'server', _('SMTP Server'));
|
||||
o.placeholder = 'smtp.example.com';
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.option(form.Value, 'port', _('Port'));
|
||||
o.datatype = 'port';
|
||||
o.default = '587';
|
||||
o.placeholder = '587';
|
||||
|
||||
o = s.option(form.Flag, 'tls', _('Use STARTTLS'));
|
||||
o.default = '1';
|
||||
o.description = _('Use STARTTLS encryption (recommended for port 587)');
|
||||
|
||||
o = s.option(form.Flag, 'ssl', _('Use SSL/TLS'));
|
||||
o.default = '0';
|
||||
o.description = _('Use implicit SSL/TLS (for port 465)');
|
||||
|
||||
o = s.option(form.Flag, 'auth', _('Authentication Required'));
|
||||
o.default = '1';
|
||||
|
||||
o = s.option(form.Value, 'user', _('Username'));
|
||||
o.depends('auth', '1');
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.option(form.Value, 'password', _('Password'));
|
||||
o.password = true;
|
||||
o.depends('auth', '1');
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.option(form.Value, 'from', _('From Address'));
|
||||
o.placeholder = 'secubox@example.com';
|
||||
o.datatype = 'email';
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.option(form.Value, 'from_name', _('From Name'));
|
||||
o.placeholder = 'SecuBox';
|
||||
o.default = 'SecuBox';
|
||||
o.rmempty = true;
|
||||
|
||||
// Recipients section
|
||||
s = m.section(form.NamedSection, 'recipients', 'recipients', _('Default Recipients'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.Value, 'admin', _('Admin Email'));
|
||||
o.datatype = 'email';
|
||||
o.description = _('Default recipient for system notifications and test emails');
|
||||
|
||||
// Test section
|
||||
s = m.section(form.NamedSection, 'main', 'smtp_relay', _('Connection Test'));
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.DummyValue, '_test', ' ');
|
||||
o.rawhtml = true;
|
||||
o.cfgvalue = function() {
|
||||
var adminEmail = uci.get('smtp-relay', 'recipients', 'admin') || '';
|
||||
return E('div', { 'style': 'display: flex; gap: 10px; align-items: center; flex-wrap: wrap;' }, [
|
||||
E('input', {
|
||||
'type': 'email',
|
||||
'id': 'test_recipient',
|
||||
'placeholder': adminEmail || _('recipient@example.com'),
|
||||
'value': adminEmail,
|
||||
'style': 'flex: 1; min-width: 200px; padding: 8px; border: 1px solid #ccc; border-radius: 4px;'
|
||||
}),
|
||||
E('button', {
|
||||
'class': 'cbi-button cbi-button-action',
|
||||
'click': ui.createHandlerFn(this, function(ev) {
|
||||
var view = document.querySelector('[data-page="smtp-relay/settings"]');
|
||||
if (view && view.handleTestEmail) {
|
||||
view.handleTestEmail(ev);
|
||||
} else {
|
||||
// Fallback
|
||||
var recipient = document.getElementById('test_recipient').value;
|
||||
var btn = ev.target;
|
||||
btn.disabled = true;
|
||||
btn.textContent = _('Sending...');
|
||||
|
||||
callTestEmail(recipient).then(function(res) {
|
||||
btn.disabled = false;
|
||||
btn.textContent = _('Send Test Email');
|
||||
var resultDiv = document.getElementById('test_result');
|
||||
if (res.success) {
|
||||
resultDiv.innerHTML = '<span style="color: #4caf50;">✓ ' + _('Test email sent!') + '</span>';
|
||||
} else {
|
||||
resultDiv.innerHTML = '<span style="color: #f44336;">✗ ' + (res.error || _('Failed')) + '</span>';
|
||||
}
|
||||
}).catch(function(err) {
|
||||
btn.disabled = false;
|
||||
btn.textContent = _('Send Test Email');
|
||||
});
|
||||
}
|
||||
})
|
||||
}, _('Send Test Email')),
|
||||
E('div', { 'id': 'test_result', 'style': 'margin-left: 10px;' })
|
||||
]);
|
||||
};
|
||||
|
||||
return m.render();
|
||||
},
|
||||
|
||||
handleSave: null,
|
||||
handleSaveApply: null,
|
||||
handleReset: null
|
||||
});
|
||||
@ -0,0 +1,169 @@
|
||||
#!/bin/sh
|
||||
# RPCD backend for SecuBox SMTP Relay
|
||||
|
||||
. /usr/share/libubox/jshn.sh
|
||||
. /lib/functions.sh
|
||||
|
||||
CONFIG="smtp-relay"
|
||||
|
||||
# Source shared library if available
|
||||
[ -f /usr/lib/secubox/mail/smtp-relay.sh ] && . /usr/lib/secubox/mail/smtp-relay.sh
|
||||
|
||||
case "$1" in
|
||||
list)
|
||||
cat << 'EOF'
|
||||
{
|
||||
"get_status": {},
|
||||
"get_config": {},
|
||||
"test_email": {"recipient": "string"},
|
||||
"send_email": {"recipient": "string", "subject": "string", "body": "string"},
|
||||
"detect_local": {}
|
||||
}
|
||||
EOF
|
||||
;;
|
||||
|
||||
call)
|
||||
case "$2" in
|
||||
get_status)
|
||||
if [ -f /usr/lib/secubox/mail/smtp-relay.sh ]; then
|
||||
smtp_relay_status
|
||||
else
|
||||
echo '{"error": "smtp-relay library not installed"}'
|
||||
fi
|
||||
;;
|
||||
|
||||
get_config)
|
||||
json_init
|
||||
|
||||
local enabled mode auto_detect
|
||||
enabled=$(uci -q get ${CONFIG}.main.enabled)
|
||||
mode=$(uci -q get ${CONFIG}.main.mode)
|
||||
auto_detect=$(uci -q get ${CONFIG}.main.auto_detect)
|
||||
|
||||
json_add_boolean "enabled" "${enabled:-0}"
|
||||
json_add_string "mode" "${mode:-external}"
|
||||
json_add_boolean "auto_detect" "${auto_detect:-1}"
|
||||
|
||||
# External settings
|
||||
json_add_object "external"
|
||||
json_add_string "server" "$(uci -q get ${CONFIG}.external.server)"
|
||||
json_add_int "port" "$(uci -q get ${CONFIG}.external.port || echo 587)"
|
||||
json_add_boolean "tls" "$(uci -q get ${CONFIG}.external.tls || echo 1)"
|
||||
json_add_boolean "ssl" "$(uci -q get ${CONFIG}.external.ssl || echo 0)"
|
||||
json_add_boolean "auth" "$(uci -q get ${CONFIG}.external.auth || echo 1)"
|
||||
json_add_string "user" "$(uci -q get ${CONFIG}.external.user)"
|
||||
local pwd_set=0
|
||||
[ -n "$(uci -q get ${CONFIG}.external.password)" ] && pwd_set=1
|
||||
json_add_boolean "password_set" "$pwd_set"
|
||||
json_add_string "from" "$(uci -q get ${CONFIG}.external.from)"
|
||||
json_add_string "from_name" "$(uci -q get ${CONFIG}.external.from_name)"
|
||||
json_close_object
|
||||
|
||||
# Local settings
|
||||
json_add_object "local"
|
||||
json_add_string "server" "$(uci -q get ${CONFIG}.local.server)"
|
||||
json_add_int "port" "$(uci -q get ${CONFIG}.local.port || echo 25)"
|
||||
json_close_object
|
||||
|
||||
# Recipients
|
||||
json_add_string "admin" "$(uci -q get ${CONFIG}.recipients.admin)"
|
||||
|
||||
json_dump
|
||||
;;
|
||||
|
||||
test_email)
|
||||
read -r input
|
||||
local recipient
|
||||
recipient=$(echo "$input" | jsonfilter -e '@.recipient' 2>/dev/null)
|
||||
|
||||
json_init
|
||||
|
||||
if [ -f /usr/lib/secubox/mail/smtp-relay.sh ]; then
|
||||
local output
|
||||
output=$(smtp_relay_test "$recipient" 2>&1)
|
||||
local code=$?
|
||||
|
||||
if [ $code -eq 0 ]; then
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "Test email sent successfully"
|
||||
else
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "$output"
|
||||
fi
|
||||
else
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "smtp-relay library not installed"
|
||||
fi
|
||||
|
||||
json_dump
|
||||
;;
|
||||
|
||||
send_email)
|
||||
read -r input
|
||||
local recipient subject body
|
||||
recipient=$(echo "$input" | jsonfilter -e '@.recipient' 2>/dev/null)
|
||||
subject=$(echo "$input" | jsonfilter -e '@.subject' 2>/dev/null)
|
||||
body=$(echo "$input" | jsonfilter -e '@.body' 2>/dev/null)
|
||||
|
||||
json_init
|
||||
|
||||
if [ -z "$recipient" ] || [ -z "$subject" ]; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "recipient and subject are required"
|
||||
json_dump
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -f /usr/lib/secubox/mail/smtp-relay.sh ]; then
|
||||
local output
|
||||
output=$(send_mail "$recipient" "$subject" "$body" 2>&1)
|
||||
local code=$?
|
||||
|
||||
if [ $code -eq 0 ]; then
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "Email sent"
|
||||
else
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "$output"
|
||||
fi
|
||||
else
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "smtp-relay library not installed"
|
||||
fi
|
||||
|
||||
json_dump
|
||||
;;
|
||||
|
||||
detect_local)
|
||||
json_init
|
||||
|
||||
local mailserver_enabled mailserver_ip detected responding
|
||||
mailserver_enabled=$(uci -q get mailserver.main.enabled)
|
||||
mailserver_ip=$(uci -q get mailserver.server.ip_address)
|
||||
[ -z "$mailserver_ip" ] && mailserver_ip=$(uci -q get mailserver.main.ip_address)
|
||||
|
||||
detected=0
|
||||
responding=0
|
||||
|
||||
if [ "$mailserver_enabled" = "1" ] && [ -n "$mailserver_ip" ]; then
|
||||
detected=1
|
||||
if nc -z "$mailserver_ip" 25 2>/dev/null; then
|
||||
responding=1
|
||||
fi
|
||||
fi
|
||||
|
||||
json_add_boolean "detected" "$detected"
|
||||
json_add_boolean "responding" "$responding"
|
||||
json_add_string "ip" "${mailserver_ip:-}"
|
||||
|
||||
json_dump
|
||||
;;
|
||||
|
||||
*)
|
||||
echo '{"error": "Unknown method"}'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@ -0,0 +1,14 @@
|
||||
{
|
||||
"admin/secubox/system/smtp-relay": {
|
||||
"title": "SMTP Relay",
|
||||
"order": 55,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "smtp-relay/settings"
|
||||
},
|
||||
"depends": {
|
||||
"acl": ["luci-app-smtp-relay"],
|
||||
"uci": {"smtp-relay": true}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
{
|
||||
"luci-app-smtp-relay": {
|
||||
"description": "Grant access to SMTP Relay configuration",
|
||||
"read": {
|
||||
"ubus": {
|
||||
"luci.smtp-relay": [
|
||||
"get_status",
|
||||
"get_config",
|
||||
"detect_local"
|
||||
]
|
||||
},
|
||||
"uci": ["smtp-relay"]
|
||||
},
|
||||
"write": {
|
||||
"ubus": {
|
||||
"luci.smtp-relay": [
|
||||
"test_email",
|
||||
"send_email"
|
||||
]
|
||||
},
|
||||
"uci": ["smtp-relay"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,15 +1,47 @@
|
||||
#!/bin/sh
|
||||
# SecuBox Reporter - Email Integration
|
||||
# Sends reports via msmtp or sendmail
|
||||
# Uses centralized SMTP relay (secubox-app-smtp-relay) or falls back to legacy config
|
||||
|
||||
. /lib/functions.sh
|
||||
|
||||
# Check if centralized SMTP relay is available and enabled
|
||||
_use_smtp_relay() {
|
||||
[ -f /usr/lib/secubox/mail/smtp-relay.sh ] || return 1
|
||||
local enabled
|
||||
enabled=$(uci -q get smtp-relay.main.enabled)
|
||||
[ "$enabled" = "1" ]
|
||||
}
|
||||
|
||||
# Send report via email
|
||||
send_report_email() {
|
||||
local report_type="$1"
|
||||
local html_content="$2"
|
||||
local recipient="$3"
|
||||
|
||||
local hostname
|
||||
hostname=$(uci -q get system.@system[0].hostname || hostname)
|
||||
local date_str
|
||||
date_str=$(date '+%Y-%m-%d')
|
||||
|
||||
# Format report type for subject
|
||||
local report_name="Status"
|
||||
case "$report_type" in
|
||||
dev) report_name="Development Status" ;;
|
||||
services) report_name="Services Distribution" ;;
|
||||
system) report_name="System Hardware" ;;
|
||||
all) report_name="Full Status" ;;
|
||||
esac
|
||||
|
||||
local subject="[SecuBox] $report_name Report - $hostname - $date_str"
|
||||
|
||||
# Use centralized SMTP relay if available
|
||||
if _use_smtp_relay; then
|
||||
. /usr/lib/secubox/mail/smtp-relay.sh
|
||||
send_html_mail "$recipient" "$subject" "$html_content"
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Legacy fallback: use per-app config
|
||||
local smtp_server=""
|
||||
local smtp_port=""
|
||||
local smtp_user=""
|
||||
@ -28,19 +60,6 @@ send_report_email() {
|
||||
return 1
|
||||
}
|
||||
|
||||
local hostname=$(uci -q get system.@system[0].hostname || hostname)
|
||||
local date_str=$(date '+%Y-%m-%d')
|
||||
|
||||
# Format report type for subject
|
||||
local report_name="Status"
|
||||
case "$report_type" in
|
||||
dev) report_name="Development Status" ;;
|
||||
services) report_name="Services Distribution" ;;
|
||||
all) report_name="Full Status" ;;
|
||||
esac
|
||||
|
||||
local subject="[SecuBox] $report_name Report - $hostname - $date_str"
|
||||
|
||||
# Build MIME multipart email
|
||||
local boundary="SecuBox_Report_$(date +%s)_$$"
|
||||
|
||||
@ -105,6 +124,15 @@ EOF
|
||||
# Test email configuration
|
||||
test_email() {
|
||||
local recipient="$1"
|
||||
|
||||
# Use centralized SMTP relay if available
|
||||
if _use_smtp_relay; then
|
||||
. /usr/lib/secubox/mail/smtp-relay.sh
|
||||
smtp_relay_test "$recipient"
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Legacy fallback
|
||||
[ -z "$recipient" ] && {
|
||||
config_load secubox-reporter
|
||||
config_get recipient email recipient ""
|
||||
@ -115,7 +143,8 @@ test_email() {
|
||||
return 1
|
||||
}
|
||||
|
||||
local hostname=$(uci -q get system.@system[0].hostname || hostname)
|
||||
local hostname
|
||||
hostname=$(uci -q get system.@system[0].hostname || hostname)
|
||||
local test_body="<html><body><h1>SecuBox Email Test</h1><p>This is a test email from <strong>$hostname</strong>.</p><p>Generated: $(date)</p></body></html>"
|
||||
|
||||
if send_report_email "test" "$test_body" "$recipient"; then
|
||||
|
||||
46
package/secubox/secubox-app-smtp-relay/Makefile
Normal file
46
package/secubox/secubox-app-smtp-relay/Makefile
Normal file
@ -0,0 +1,46 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=secubox-app-smtp-relay
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_MAINTAINER:=SecuBox Team <contact@secubox.io>
|
||||
PKG_LICENSE:=GPL-3.0
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/secubox-app-smtp-relay
|
||||
SECTION:=secubox
|
||||
CATEGORY:=SecuBox
|
||||
SUBMENU:=System
|
||||
TITLE:=SecuBox Unified SMTP Relay
|
||||
DEPENDS:=+msmtp
|
||||
PKGARCH:=all
|
||||
endef
|
||||
|
||||
define Package/secubox-app-smtp-relay/description
|
||||
Centralized SMTP relay configuration for all SecuBox services.
|
||||
Provides a shared mail library and CLI tool for sending emails.
|
||||
Supports external SMTP servers, local mailserver auto-detection,
|
||||
and direct delivery modes.
|
||||
endef
|
||||
|
||||
define Package/secubox-app-smtp-relay/conffiles
|
||||
/etc/config/smtp-relay
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
endef
|
||||
|
||||
define Package/secubox-app-smtp-relay/install
|
||||
$(INSTALL_DIR) $(1)/etc/config
|
||||
$(INSTALL_CONF) ./files/etc/config/smtp-relay $(1)/etc/config/smtp-relay
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_BIN) ./files/usr/sbin/smtp-relayctl $(1)/usr/sbin/smtp-relayctl
|
||||
|
||||
$(INSTALL_DIR) $(1)/usr/lib/secubox/mail
|
||||
$(INSTALL_DATA) ./files/usr/lib/secubox/mail/smtp-relay.sh $(1)/usr/lib/secubox/mail/smtp-relay.sh
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,secubox-app-smtp-relay))
|
||||
@ -0,0 +1,41 @@
|
||||
# SecuBox SMTP Relay Configuration
|
||||
# Centralized outbound email settings for all SecuBox services
|
||||
|
||||
config smtp_relay 'main'
|
||||
option enabled '0'
|
||||
# Mode: external (configured SMTP), local (auto-detected mailserver), direct (MTA)
|
||||
option mode 'external'
|
||||
# Auto-detect local mailserver (secubox-app-mailserver) if running
|
||||
option auto_detect '1'
|
||||
|
||||
# External SMTP provider settings
|
||||
config external 'external'
|
||||
option server ''
|
||||
option port '587'
|
||||
# TLS mode: 0=none, 1=STARTTLS
|
||||
option tls '1'
|
||||
# SSL mode: 0=STARTTLS, 1=implicit SSL (port 465)
|
||||
option ssl '0'
|
||||
option auth '1'
|
||||
option user ''
|
||||
option password ''
|
||||
option from ''
|
||||
option from_name 'SecuBox'
|
||||
|
||||
# Local mailserver settings (auto-populated from secubox-app-mailserver)
|
||||
config local 'local'
|
||||
option server '127.0.0.1'
|
||||
option port '25'
|
||||
option tls '0'
|
||||
option auth '0'
|
||||
option from ''
|
||||
|
||||
# Direct delivery settings (when port 25 is open)
|
||||
config direct 'direct'
|
||||
option helo_domain ''
|
||||
|
||||
# Default recipients for system notifications
|
||||
config recipients 'recipients'
|
||||
option admin ''
|
||||
# Additional notification recipients (list)
|
||||
# list notify 'user@example.com'
|
||||
@ -0,0 +1,280 @@
|
||||
#!/bin/sh
|
||||
# SecuBox SMTP Relay - Shared Mail Library
|
||||
# Source this file to use send_mail() in any SecuBox app
|
||||
#
|
||||
# Usage:
|
||||
# . /usr/lib/secubox/mail/smtp-relay.sh
|
||||
# send_mail "user@example.com" "Subject" "Body text"
|
||||
# send_html_mail "user@example.com" "Subject" "<h1>HTML Body</h1>"
|
||||
|
||||
. /lib/functions.sh
|
||||
|
||||
SMTP_CONFIG="smtp-relay"
|
||||
|
||||
# Global variables set by smtp_relay_load_config
|
||||
smtp_enabled=""
|
||||
smtp_mode=""
|
||||
smtp_server=""
|
||||
smtp_port=""
|
||||
smtp_tls=""
|
||||
smtp_ssl=""
|
||||
smtp_auth=""
|
||||
smtp_user=""
|
||||
smtp_password=""
|
||||
smtp_from=""
|
||||
smtp_from_name=""
|
||||
smtp_admin=""
|
||||
smtp_helo=""
|
||||
|
||||
# Load SMTP configuration from UCI
|
||||
smtp_relay_load_config() {
|
||||
config_load "$SMTP_CONFIG"
|
||||
|
||||
config_get smtp_enabled main enabled '0'
|
||||
config_get smtp_mode main mode 'external'
|
||||
config_get auto_detect main auto_detect '1'
|
||||
|
||||
# Auto-detect local mailserver if enabled
|
||||
if [ "$auto_detect" = "1" ] && [ "$smtp_mode" = "external" ]; then
|
||||
local mailserver_enabled mailserver_ip
|
||||
mailserver_enabled=$(uci -q get mailserver.main.enabled)
|
||||
mailserver_ip=$(uci -q get mailserver.server.ip_address)
|
||||
[ -z "$mailserver_ip" ] && mailserver_ip=$(uci -q get mailserver.main.ip_address)
|
||||
[ -z "$mailserver_ip" ] && mailserver_ip="127.0.0.1"
|
||||
|
||||
if [ "$mailserver_enabled" = "1" ]; then
|
||||
# Check if mailserver is responsive on SMTP port
|
||||
if nc -z "$mailserver_ip" 25 2>/dev/null; then
|
||||
smtp_mode="local"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Load mode-specific settings
|
||||
case "$smtp_mode" in
|
||||
external)
|
||||
config_get smtp_server external server ''
|
||||
config_get smtp_port external port '587'
|
||||
config_get smtp_tls external tls '1'
|
||||
config_get smtp_ssl external ssl '0'
|
||||
config_get smtp_auth external auth '1'
|
||||
config_get smtp_user external user ''
|
||||
config_get smtp_password external password ''
|
||||
config_get smtp_from external from ''
|
||||
config_get smtp_from_name external from_name 'SecuBox'
|
||||
;;
|
||||
local)
|
||||
config_get smtp_server local server '127.0.0.1'
|
||||
config_get smtp_port local port '25'
|
||||
config_get smtp_tls local tls '0'
|
||||
config_get smtp_ssl local ssl '0'
|
||||
config_get smtp_auth local auth '0'
|
||||
config_get smtp_user local user ''
|
||||
config_get smtp_password local password ''
|
||||
config_get smtp_from local from ''
|
||||
smtp_from_name="SecuBox"
|
||||
;;
|
||||
direct)
|
||||
smtp_server=""
|
||||
smtp_port="25"
|
||||
smtp_tls="0"
|
||||
smtp_ssl="0"
|
||||
smtp_auth="0"
|
||||
config_get smtp_helo direct helo_domain ''
|
||||
;;
|
||||
esac
|
||||
|
||||
# Load default recipients
|
||||
config_get smtp_admin recipients admin ''
|
||||
}
|
||||
|
||||
# Build msmtp configuration file
|
||||
# Arguments: $1 - output file path (optional)
|
||||
# Returns: path to temp config file
|
||||
smtp_relay_build_msmtp_config() {
|
||||
local conf_file="${1:-/tmp/msmtp-relay-$$.conf}"
|
||||
local hostname
|
||||
hostname=$(uci -q get system.@system[0].hostname || hostname)
|
||||
|
||||
local tls_mode="off"
|
||||
local tls_starttls="off"
|
||||
|
||||
if [ "$smtp_ssl" = "1" ]; then
|
||||
tls_mode="on"
|
||||
tls_starttls="off"
|
||||
elif [ "$smtp_tls" = "1" ]; then
|
||||
tls_mode="on"
|
||||
tls_starttls="on"
|
||||
fi
|
||||
|
||||
cat > "$conf_file" << EOF
|
||||
account default
|
||||
host ${smtp_server}
|
||||
port ${smtp_port}
|
||||
auth $([ "$smtp_auth" = "1" ] && echo "on" || echo "off")
|
||||
user ${smtp_user}
|
||||
password ${smtp_password}
|
||||
tls ${tls_mode}
|
||||
tls_starttls ${tls_starttls}
|
||||
tls_certcheck off
|
||||
from ${smtp_from:-secubox@$hostname}
|
||||
EOF
|
||||
chmod 600 "$conf_file"
|
||||
echo "$conf_file"
|
||||
}
|
||||
|
||||
# Send email via SMTP relay
|
||||
# Arguments:
|
||||
# $1 - recipient email
|
||||
# $2 - subject
|
||||
# $3 - body (plain text or HTML)
|
||||
# $4 - content type (optional: "text/plain" or "text/html", default: auto-detect)
|
||||
# Returns: 0 on success, 1 on failure
|
||||
send_mail() {
|
||||
local recipient="$1"
|
||||
local subject="$2"
|
||||
local body="$3"
|
||||
local content_type="${4:-}"
|
||||
|
||||
# Load configuration
|
||||
smtp_relay_load_config
|
||||
|
||||
[ "$smtp_enabled" != "1" ] && {
|
||||
echo "ERROR: SMTP relay is disabled" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# Use admin email if no recipient specified
|
||||
[ -z "$recipient" ] && recipient="$smtp_admin"
|
||||
|
||||
[ -z "$recipient" ] && {
|
||||
echo "ERROR: No recipient specified" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
local hostname
|
||||
hostname=$(uci -q get system.@system[0].hostname || hostname)
|
||||
local from_addr="${smtp_from:-secubox@$hostname}"
|
||||
local from_header="${smtp_from_name} <${from_addr}>"
|
||||
|
||||
# Auto-detect content type from body
|
||||
if [ -z "$content_type" ]; then
|
||||
if echo "$body" | grep -qE '<html|<body|<div|<p>|<h[1-6]>|<table'; then
|
||||
content_type="text/html"
|
||||
else
|
||||
content_type="text/plain"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Build email headers
|
||||
local date_rfc
|
||||
date_rfc=$(date -R 2>/dev/null || date)
|
||||
|
||||
local email_content
|
||||
email_content="Date: ${date_rfc}
|
||||
From: ${from_header}
|
||||
To: ${recipient}
|
||||
Subject: ${subject}
|
||||
MIME-Version: 1.0
|
||||
Content-Type: ${content_type}; charset=utf-8
|
||||
X-Mailer: SecuBox SMTP Relay 1.0
|
||||
|
||||
${body}"
|
||||
|
||||
# Try msmtp first (for external and local modes)
|
||||
if command -v msmtp >/dev/null 2>&1 && [ "$smtp_mode" != "direct" ]; then
|
||||
local msmtp_conf
|
||||
msmtp_conf=$(smtp_relay_build_msmtp_config)
|
||||
echo "$email_content" | msmtp -C "$msmtp_conf" "$recipient" 2>&1
|
||||
local result=$?
|
||||
rm -f "$msmtp_conf"
|
||||
return $result
|
||||
fi
|
||||
|
||||
# Fallback to sendmail (for direct mode or if msmtp unavailable)
|
||||
if command -v sendmail >/dev/null 2>&1; then
|
||||
echo "$email_content" | sendmail -t 2>&1
|
||||
return $?
|
||||
fi
|
||||
|
||||
echo "ERROR: No mail transport available (msmtp or sendmail required)" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# Send HTML email (convenience wrapper)
|
||||
send_html_mail() {
|
||||
send_mail "$1" "$2" "$3" "text/html"
|
||||
}
|
||||
|
||||
# Send plain text email (convenience wrapper)
|
||||
send_text_mail() {
|
||||
send_mail "$1" "$2" "$3" "text/plain"
|
||||
}
|
||||
|
||||
# Test SMTP configuration by sending a test email
|
||||
# Arguments: $1 - recipient (optional, uses admin if not specified)
|
||||
# Returns: 0 on success, 1 on failure
|
||||
smtp_relay_test() {
|
||||
local recipient="${1:-}"
|
||||
|
||||
smtp_relay_load_config
|
||||
|
||||
[ -z "$recipient" ] && recipient="$smtp_admin"
|
||||
[ -z "$recipient" ] && {
|
||||
echo "ERROR: No test recipient available (set admin email in config)" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
local hostname
|
||||
hostname=$(uci -q get system.@system[0].hostname || hostname)
|
||||
|
||||
local test_body="This is a test email from SecuBox SMTP Relay.
|
||||
|
||||
Hostname: ${hostname}
|
||||
Mode: ${smtp_mode}
|
||||
Server: ${smtp_server:-direct delivery}
|
||||
Port: ${smtp_port}
|
||||
TLS: $([ "$smtp_tls" = "1" ] && echo "Yes" || echo "No")
|
||||
Time: $(date)
|
||||
|
||||
If you received this message, your SMTP configuration is working correctly."
|
||||
|
||||
send_mail "$recipient" "[SecuBox] SMTP Test - $hostname" "$test_body"
|
||||
}
|
||||
|
||||
# Get SMTP relay status as JSON
|
||||
smtp_relay_status() {
|
||||
smtp_relay_load_config
|
||||
|
||||
local mailserver_detected="false"
|
||||
local mailserver_ip
|
||||
mailserver_ip=$(uci -q get mailserver.server.ip_address)
|
||||
[ -z "$mailserver_ip" ] && mailserver_ip=$(uci -q get mailserver.main.ip_address)
|
||||
|
||||
if [ -n "$mailserver_ip" ] && nc -z "$mailserver_ip" 25 2>/dev/null; then
|
||||
mailserver_detected="true"
|
||||
fi
|
||||
|
||||
local msmtp_available="false"
|
||||
local sendmail_available="false"
|
||||
command -v msmtp >/dev/null 2>&1 && msmtp_available="true"
|
||||
command -v sendmail >/dev/null 2>&1 && sendmail_available="true"
|
||||
|
||||
cat << EOF
|
||||
{
|
||||
"enabled": $([ "$smtp_enabled" = "1" ] && echo "true" || echo "false"),
|
||||
"mode": "${smtp_mode}",
|
||||
"server": "${smtp_server:-}",
|
||||
"port": ${smtp_port:-587},
|
||||
"tls": $([ "$smtp_tls" = "1" ] && echo "true" || echo "false"),
|
||||
"ssl": $([ "$smtp_ssl" = "1" ] && echo "true" || echo "false"),
|
||||
"auth": $([ "$smtp_auth" = "1" ] && echo "true" || echo "false"),
|
||||
"from": "${smtp_from:-}",
|
||||
"from_name": "${smtp_from_name:-SecuBox}",
|
||||
"admin_recipient": "${smtp_admin:-}",
|
||||
"local_mailserver_detected": ${mailserver_detected},
|
||||
"msmtp_available": ${msmtp_available},
|
||||
"sendmail_available": ${sendmail_available}
|
||||
}
|
||||
EOF
|
||||
}
|
||||
@ -0,0 +1,350 @@
|
||||
#!/bin/sh
|
||||
# SecuBox SMTP Relay Controller
|
||||
# CLI tool for managing centralized SMTP configuration
|
||||
|
||||
VERSION="1.0.0"
|
||||
CONFIG="smtp-relay"
|
||||
|
||||
# Source shared library
|
||||
. /usr/lib/secubox/mail/smtp-relay.sh
|
||||
|
||||
# Colors (disabled if not terminal)
|
||||
if [ -t 1 ]; then
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m'
|
||||
else
|
||||
RED='' GREEN='' YELLOW='' CYAN='' BOLD='' NC=''
|
||||
fi
|
||||
|
||||
log() { echo -e "${GREEN}[SMTP]${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
|
||||
|
||||
# Show current status
|
||||
cmd_status() {
|
||||
smtp_relay_load_config
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD}========================================"
|
||||
echo -e " SecuBox SMTP Relay v$VERSION"
|
||||
echo -e "========================================${NC}"
|
||||
echo ""
|
||||
echo -e " Enabled: $([ "$smtp_enabled" = "1" ] && echo -e "${GREEN}Yes${NC}" || echo -e "${RED}No${NC}")"
|
||||
echo -e " Mode: ${CYAN}$smtp_mode${NC}"
|
||||
echo ""
|
||||
|
||||
case "$smtp_mode" in
|
||||
external)
|
||||
echo " Server: ${smtp_server:-${YELLOW}not configured${NC}}"
|
||||
echo " Port: ${smtp_port}"
|
||||
echo " TLS: $([ "$smtp_tls" = "1" ] && echo "STARTTLS" || ([ "$smtp_ssl" = "1" ] && echo "SSL/TLS" || echo "None"))"
|
||||
echo " Auth: $([ "$smtp_auth" = "1" ] && echo "Yes (user: $smtp_user)" || echo "No")"
|
||||
echo " From: ${smtp_from:-auto}"
|
||||
;;
|
||||
local)
|
||||
echo " Server: ${smtp_server} (local mailserver)"
|
||||
echo " Port: ${smtp_port}"
|
||||
;;
|
||||
direct)
|
||||
echo " Mode: Direct MTA delivery"
|
||||
echo " HELO: ${smtp_helo:-auto}"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo -e " Admin Email: ${smtp_admin:-${YELLOW}not set${NC}}"
|
||||
echo ""
|
||||
|
||||
# Transport availability
|
||||
echo -e "${BOLD}Transport:${NC}"
|
||||
if command -v msmtp >/dev/null 2>&1; then
|
||||
echo -e " msmtp: ${GREEN}Available${NC}"
|
||||
else
|
||||
echo -e " msmtp: ${RED}Not installed${NC}"
|
||||
fi
|
||||
|
||||
if command -v sendmail >/dev/null 2>&1; then
|
||||
echo -e " sendmail: ${GREEN}Available${NC}"
|
||||
else
|
||||
echo -e " sendmail: ${YELLOW}Not available${NC}"
|
||||
fi
|
||||
|
||||
# Check local mailserver
|
||||
local mailserver_ip
|
||||
mailserver_ip=$(uci -q get mailserver.server.ip_address)
|
||||
[ -z "$mailserver_ip" ] && mailserver_ip=$(uci -q get mailserver.main.ip_address)
|
||||
|
||||
if [ -n "$mailserver_ip" ]; then
|
||||
if nc -z "$mailserver_ip" 25 2>/dev/null; then
|
||||
echo -e " Local Mail: ${GREEN}Running ($mailserver_ip)${NC}"
|
||||
else
|
||||
echo -e " Local Mail: ${YELLOW}Not responding ($mailserver_ip)${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e " Local Mail: ${YELLOW}Not configured${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Send test email
|
||||
cmd_test() {
|
||||
local recipient="$1"
|
||||
|
||||
log "Testing SMTP configuration..."
|
||||
|
||||
if smtp_relay_test "$recipient"; then
|
||||
log "Test email sent successfully!"
|
||||
return 0
|
||||
else
|
||||
error "Failed to send test email"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Send email from CLI
|
||||
cmd_send() {
|
||||
local recipient="$1"
|
||||
local subject="$2"
|
||||
local body="$3"
|
||||
|
||||
if [ -z "$recipient" ] || [ -z "$subject" ]; then
|
||||
echo "Usage: smtp-relayctl send <recipient> <subject> [body]"
|
||||
echo " If body is omitted, reads from stdin"
|
||||
return 1
|
||||
fi
|
||||
|
||||
[ -z "$body" ] && body=$(cat)
|
||||
|
||||
if send_mail "$recipient" "$subject" "$body"; then
|
||||
log "Email sent to $recipient"
|
||||
return 0
|
||||
else
|
||||
error "Failed to send email"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Interactive configuration
|
||||
cmd_configure() {
|
||||
local mode="$1"
|
||||
|
||||
case "$mode" in
|
||||
external)
|
||||
echo -e "${BOLD}Configuring External SMTP${NC}"
|
||||
echo ""
|
||||
|
||||
printf "SMTP Server: "
|
||||
read -r server
|
||||
[ -z "$server" ] && { error "Server is required"; return 1; }
|
||||
|
||||
printf "Port [587]: "
|
||||
read -r port
|
||||
port=${port:-587}
|
||||
|
||||
printf "Use STARTTLS? [Y/n]: "
|
||||
read -r tls_yn
|
||||
tls_yn=${tls_yn:-Y}
|
||||
|
||||
printf "Authentication required? [Y/n]: "
|
||||
read -r auth_yn
|
||||
auth_yn=${auth_yn:-Y}
|
||||
|
||||
local user="" password=""
|
||||
if [ "$auth_yn" != "n" ] && [ "$auth_yn" != "N" ]; then
|
||||
printf "Username: "
|
||||
read -r user
|
||||
|
||||
printf "Password: "
|
||||
stty -echo 2>/dev/null
|
||||
read -r password
|
||||
stty echo 2>/dev/null
|
||||
echo ""
|
||||
fi
|
||||
|
||||
printf "From email address: "
|
||||
read -r from_email
|
||||
|
||||
printf "From name [SecuBox]: "
|
||||
read -r from_name
|
||||
from_name=${from_name:-SecuBox}
|
||||
|
||||
# Save configuration
|
||||
uci set ${CONFIG}.main.mode='external'
|
||||
uci set ${CONFIG}.main.enabled='1'
|
||||
uci set ${CONFIG}.external.server="$server"
|
||||
uci set ${CONFIG}.external.port="$port"
|
||||
uci set ${CONFIG}.external.tls=$([ "$tls_yn" = "n" ] || [ "$tls_yn" = "N" ] && echo "0" || echo "1")
|
||||
uci set ${CONFIG}.external.auth=$([ "$auth_yn" = "n" ] || [ "$auth_yn" = "N" ] && echo "0" || echo "1")
|
||||
uci set ${CONFIG}.external.user="$user"
|
||||
uci set ${CONFIG}.external.password="$password"
|
||||
uci set ${CONFIG}.external.from="$from_email"
|
||||
uci set ${CONFIG}.external.from_name="$from_name"
|
||||
uci commit ${CONFIG}
|
||||
|
||||
log "External SMTP configured successfully"
|
||||
echo ""
|
||||
echo "Test with: smtp-relayctl test your@email.com"
|
||||
;;
|
||||
|
||||
local)
|
||||
local mailserver_ip
|
||||
mailserver_ip=$(uci -q get mailserver.server.ip_address)
|
||||
[ -z "$mailserver_ip" ] && mailserver_ip=$(uci -q get mailserver.main.ip_address)
|
||||
|
||||
if [ -z "$mailserver_ip" ]; then
|
||||
error "Local mailserver not configured"
|
||||
echo "Install secubox-app-mailserver first"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! nc -z "$mailserver_ip" 25 2>/dev/null; then
|
||||
warn "Local mailserver not responding on $mailserver_ip:25"
|
||||
printf "Continue anyway? [y/N]: "
|
||||
read -r cont
|
||||
[ "$cont" != "y" ] && [ "$cont" != "Y" ] && return 1
|
||||
fi
|
||||
|
||||
uci set ${CONFIG}.main.mode='local'
|
||||
uci set ${CONFIG}.main.enabled='1'
|
||||
uci set ${CONFIG}.local.server="$mailserver_ip"
|
||||
uci commit ${CONFIG}
|
||||
|
||||
log "Local mailserver configured ($mailserver_ip)"
|
||||
;;
|
||||
|
||||
direct)
|
||||
warn "Direct delivery requires port 25 to be open to the internet"
|
||||
printf "HELO domain (leave empty for auto): "
|
||||
read -r helo
|
||||
|
||||
uci set ${CONFIG}.main.mode='direct'
|
||||
uci set ${CONFIG}.main.enabled='1'
|
||||
[ -n "$helo" ] && uci set ${CONFIG}.direct.helo_domain="$helo"
|
||||
uci commit ${CONFIG}
|
||||
|
||||
log "Direct delivery mode configured"
|
||||
;;
|
||||
|
||||
"")
|
||||
echo "Usage: smtp-relayctl configure <mode>"
|
||||
echo ""
|
||||
echo "Modes:"
|
||||
echo " external - Use external SMTP server (Gmail, SendGrid, etc.)"
|
||||
echo " local - Use local mailserver (secubox-app-mailserver)"
|
||||
echo " direct - Direct MTA delivery (requires port 25 open)"
|
||||
return 1
|
||||
;;
|
||||
|
||||
*)
|
||||
error "Unknown mode: $mode"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Set admin email
|
||||
cmd_admin() {
|
||||
local email="$1"
|
||||
|
||||
if [ -z "$email" ]; then
|
||||
local current
|
||||
current=$(uci -q get ${CONFIG}.recipients.admin)
|
||||
if [ -n "$current" ]; then
|
||||
echo "Current admin email: $current"
|
||||
else
|
||||
echo "No admin email configured"
|
||||
fi
|
||||
echo ""
|
||||
echo "Usage: smtp-relayctl admin <email>"
|
||||
return 0
|
||||
fi
|
||||
|
||||
uci set ${CONFIG}.recipients.admin="$email"
|
||||
uci commit ${CONFIG}
|
||||
log "Admin email set to: $email"
|
||||
}
|
||||
|
||||
# Enable/disable relay
|
||||
cmd_enable() {
|
||||
uci set ${CONFIG}.main.enabled='1'
|
||||
uci commit ${CONFIG}
|
||||
log "SMTP relay enabled"
|
||||
}
|
||||
|
||||
cmd_disable() {
|
||||
uci set ${CONFIG}.main.enabled='0'
|
||||
uci commit ${CONFIG}
|
||||
log "SMTP relay disabled"
|
||||
}
|
||||
|
||||
# Output JSON status
|
||||
cmd_json() {
|
||||
smtp_relay_status
|
||||
}
|
||||
|
||||
# Show help
|
||||
show_help() {
|
||||
cat << EOF
|
||||
SecuBox SMTP Relay v$VERSION
|
||||
|
||||
Centralized SMTP configuration for all SecuBox services.
|
||||
|
||||
Usage: smtp-relayctl <command> [options]
|
||||
|
||||
Commands:
|
||||
status Show SMTP configuration status
|
||||
test [recipient] Send test email
|
||||
send <to> <subject> [body] Send email (body from stdin if omitted)
|
||||
configure <mode> Interactive configuration
|
||||
admin [email] Show/set admin email address
|
||||
enable Enable SMTP relay
|
||||
disable Disable SMTP relay
|
||||
json Output status as JSON
|
||||
|
||||
Configuration modes:
|
||||
external Use external SMTP server (Gmail, SendGrid, etc.)
|
||||
local Use local mailserver (secubox-app-mailserver)
|
||||
direct Direct MTA delivery (requires port 25 open)
|
||||
|
||||
Examples:
|
||||
smtp-relayctl status
|
||||
smtp-relayctl configure external
|
||||
smtp-relayctl test admin@example.com
|
||||
smtp-relayctl admin notifications@mydomain.com
|
||||
echo "Hello" | smtp-relayctl send user@example.com "Test Subject"
|
||||
|
||||
Configuration: /etc/config/smtp-relay
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# Main command dispatcher
|
||||
case "${1:-}" in
|
||||
status) shift; cmd_status "$@" ;;
|
||||
test) shift; cmd_test "$@" ;;
|
||||
send) shift; cmd_send "$@" ;;
|
||||
configure) shift; cmd_configure "$@" ;;
|
||||
admin) shift; cmd_admin "$@" ;;
|
||||
enable) shift; cmd_enable "$@" ;;
|
||||
disable) shift; cmd_disable "$@" ;;
|
||||
json) shift; cmd_json "$@" ;;
|
||||
help|--help|-h)
|
||||
show_help
|
||||
;;
|
||||
'')
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
error "Unknown command: $1"
|
||||
echo ""
|
||||
show_help >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
Loading…
Reference in New Issue
Block a user