smtp support

This commit is contained in:
Madpeter 2025-02-06 03:48:55 +00:00
parent 07bd928747
commit 3792241774
7 changed files with 387 additions and 3 deletions

View file

@ -135,8 +135,22 @@ ENV basic_Username='' \
chatgpt_RedisCountIm='60' \
onevent_Enabled='false' \
onevent_Count=0 \
onevent_HideStatusOutput='false'
onevent_HideStatusOutput='false' \
smtp_Enabled='false' \
smtp_AllowEmailAsReplyTarget='false' \
smtp_AllowCommandSendMail='false' \
smtp_UseAllowedRecivers='false' \
smtp_AllowedReciversCSV='none' \
smtp_AllowSendAlertStatus='false' \
smtp_AllowSendLoginNotice='false' \
smtp_MailReplyAddress='me@myemail.tld' \
smtp_Port='587' \
smtp_Host='smtp.mail.example' \
smtp_useSSL='false' \
smtp_User='me@email.addr.tld' \
smtp_Token='none' \
smtp_SendAlertsAndLoginsTo='me@somewhere.tld' \
smtp_HideStatusOutput='false'
EXPOSE 80
ENV ASPNETCORE_URLS http://+:80

View file

@ -13,6 +13,34 @@ namespace SecondBotEvents.Commands
{
}
[About("use the SMTP service to send a email (requires AllowCommandSendMail to be true)")]
[ReturnHints("sending")]
[ReturnHintsFailure("Send was rejected because: X")]
[ReturnHintsFailure("ARG is empty")]
[ArgHints("to", "the email addres to send to")]
[ArgHints("subject", "the subject of the email")]
[ArgHints("body", "the contents of the email")]
public object SendEmail(string to, string subject, string body)
{
if (SecondbotHelpers.isempty(to) == true) {
return Failure("to is empty");
}
else if (SecondbotHelpers.isempty(subject) == true)
{
return Failure("subject is empty", [ to ]);
}
else if (SecondbotHelpers.isempty(body) == true)
{
return Failure("body is empty", [to, subject]);
}
KeyValuePair<bool, string> reply = master.SmtpService.commandEmail(to, subject, body);
if(reply.Key == false)
{
return Failure("Send was rejected because: "+reply.Value, [ to, subject, body ]);
}
return BasicReply("sending",[to,subject,body]);
}
[About("Makes the bot teleport to its home region")]
[ReturnHints("ok")]
public object GoHome()

View file

@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SecondBotEvents.Config
{
public class SmtpConfig : Config
{
public SmtpConfig(bool fromENV, string fromFolder = "") : base(fromENV, fromFolder) { }
protected override void MakeSettings()
{
filename = "smtp";
settings.Add("Enabled");
settings.Add("AllowEmailAsReplyTarget");
settings.Add("AllowCommandSendMail");
settings.Add("UseAllowedRecivers");
settings.Add("AllowedReciversCSV");
settings.Add("AllowSendAlertStatus");
settings.Add("AllowSendLoginNotice");
settings.Add("MailReplyAddress");
settings.Add("Port");
settings.Add("Host");
settings.Add("useSSL");
settings.Add("User");
settings.Add("Token");
settings.Add("SendAlertsAndLoginsTo");
settings.Add("HideStatusOutput");
}
public bool GetUseAllowedRecivers()
{
return ReadSettingAsBool("UseAllowedRecivers", false);
}
public string[] GetAllowedRecivers()
{
return ReadSettingAsString("AllowedReciversCSV", "none").Split(',');
}
public bool GetUseSSL()
{
return ReadSettingAsBool("useSSL", false);
}
public string GetMailReplyAddress()
{
return ReadSettingAsString("MailReplyAddress", "me@myemail.tld");
}
public string GetSendAlertsAndLoginsTo()
{
return ReadSettingAsString("SendAlertsAndLoginsTo", "me@somewhere.tld");
}
public int GetPort()
{
return ReadSettingAsInt("Port", 587);
}
public string GetHost()
{
return ReadSettingAsString("Host", "smtp.mail.example");
}
public string GetUser()
{
return ReadSettingAsString("User", "me@email.addr.tld");
}
public string GetToken()
{
return ReadSettingAsString("Token", "none");
}
public bool GetEnabled()
{
return ReadSettingAsBool("Enabled", false);
}
public bool GetAllowEmailAsReplyTarget()
{
return ReadSettingAsBool("AllowEmailAsReplyTarget", false);
}
public bool GetAllowCommandSendMail()
{
return ReadSettingAsBool("AllowCommandSendMail", false);
}
public bool GetAllowSendAlertStatus()
{
return ReadSettingAsBool("AllowSendAlertStatus", false);
}
public bool GetAllowSendLoginNotice()
{
return ReadSettingAsBool("AllowSendLoginNotice", false);
}
}
}

View file

@ -41,7 +41,9 @@ namespace SecondBotEvents
public HomeboundService HomeboundService { get { return (HomeboundService)GetService("HomeboundService"); } }
public EventsService EventsService { get { return (EventsService)GetService("EventsService"); } }
public DialogService DialogService { get { return (DialogService)GetService("DialogService"); } }
public SmtpService SmtpService { get { return (SmtpService)GetService("SmtpService"); } }
public ChatGptService ChatGptService { get { return (ChatGptService)GetService("ChatGptService"); } }
public TriggerOnEventService TriggerOnEventService { get { return (TriggerOnEventService)GetService("TriggerOnEventService"); } }
@ -174,6 +176,7 @@ namespace SecondBotEvents
RegisterService("RelayService");
RegisterService("ChatGptService");
RegisterService("RecoveryService");
RegisterService("SmtpService");
if (BotClient.IsLoaded() == false)
{
LogFormater.Info("Config is not loaded :(");

View file

@ -17,6 +17,7 @@
<PackageReference Include="Discord.Net" Version="3.17.1" />
<PackageReference Include="Discord.Net.WebSocket" Version="3.17.1" />
<PackageReference Include="EmbedIO" Version="3.4.3" />
<PackageReference Include="MailKit" Version="4.10.0" />
<PackageReference Include="MSBuildGitHash" Version="2.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View file

@ -9,6 +9,7 @@ using System.Linq;
using System.Reflection;
using System.Net.Http;
using OpenMetaverse.ImportExport.Collada14;
using System.ComponentModel.DataAnnotations;
namespace SecondBotEvents.Services
{
@ -252,6 +253,10 @@ namespace SecondBotEvents.Services
mode = "IM";
UUID.TryParse(UUIDfetch, out target_avatar);
}
else if (new EmailAddressAttribute().IsValid(target) == true)
{
mode = "EMAIL";
}
else if (int.TryParse(target, out target_channel) == false)
{
return;
@ -287,6 +292,14 @@ namespace SecondBotEvents.Services
LogFormater.Crit("[SmartReply] HTTP failed: " + e.Message + "");
}
}
else if(mode == "EMAIL")
{
KeyValuePair<bool,string> reply = master.SmtpService.sendReplyTarget(target,command,output);
if(reply.Key == false)
{
LogFormater.Crit("[SmartReply] EMAIL failed: " + reply.Value);
}
}
}
protected HttpClient HTTPclient = new HttpClient();

View file

@ -0,0 +1,228 @@
using MailKit.Net.Imap;
using MailKit.Net.Smtp;
using MimeKit;
using OpenMetaverse;
using SecondBotEvents.Config;
using System;
using System.Collections.Generic;
using System.Linq;
namespace SecondBotEvents.Services
{
public class SmtpService : BotServices
{
protected new SmtpConfig myConfig;
protected int sent = 0;
protected int failed = 0;
protected bool botConnected = false;
public SmtpService(EventsSecondBot setMaster) : base(setMaster)
{
myConfig = new SmtpConfig(master.fromEnv, master.fromFolder);
if (myConfig.GetEnabled() == false)
{
return;
}
}
public override string Status()
{
if (myConfig == null)
{
return "No Config";
}
else if(myConfig.GetEnabled() == false)
{
return "Disabled";
}
else if (myConfig.GetHideStatusOutput() == true)
{
return "hidden";
}
else if(botConnected == false)
{
return "Standby";
}
return "send: "+sent.ToString()+" ~ Failed: "+failed.ToString();
}
protected void BotAlertMessage(object o, AlertMessageEventArgs e)
{
if (myConfig == null)
{
return;
}
else if (myConfig.GetEnabled() == false)
{
return;
}
if (myConfig.GetAllowSendAlertStatus() == false)
{
return;
}
if(myConfig.GetSendAlertsAndLoginsTo() == "me@somewhere.tld")
{
return;
}
SendMail("Bot - Alert message",e.Message, myConfig.GetSendAlertsAndLoginsTo());
}
public KeyValuePair<bool,string> commandEmail(string to,string subject, string message)
{
if(myConfig == null)
{
return new KeyValuePair<bool, string>(false,"No SMTP config");
}
else if(myConfig.GetEnabled() == false)
{
return new KeyValuePair<bool, string>(false, "SMTP service not enabled");
}
else if(myConfig.GetAllowCommandSendMail() == false)
{
return new KeyValuePair<bool, string>(false, "Send email via commands not enabled");
}
return SendMail(subject, message, to);
}
public KeyValuePair<bool, string> sendReplyTarget(string to,string command,string output)
{
if (myConfig == null)
{
return new KeyValuePair<bool, string>(false, "No SMTP config");
}
else if (myConfig.GetEnabled() == false)
{
return new KeyValuePair<bool, string>(false, "SMTP service not enabled");
}
else if (myConfig.GetAllowEmailAsReplyTarget() == false)
{
return new KeyValuePair<bool, string>(false, "Send email via command reply is not enabled");
}
return SendMail(command+"##commandreply", output, to);
}
protected KeyValuePair<bool, string> SendMail(string subject, string body, string to)
{
if(myConfig.GetMailReplyAddress() == "me@myemail.tld")
{
LogFormater.Crit("you need to set the reply address");
failed++;
return new KeyValuePair<bool, string>(false, "you need to set the reply address");
}
if(myConfig.GetUseAllowedRecivers() == true)
{
if(myConfig.GetAllowedRecivers().Contains(to) == false)
{
return new KeyValuePair<bool, string>(false, to + " is not in allowed recivers");
}
}
try
{
MimeMessage message = new MimeMessage();
message.From.Add(new MailboxAddress(myConfig.GetMailReplyAddress() + " via secondbot", myConfig.GetMailReplyAddress()));
message.To.Add(new MailboxAddress(to, to));
message.Subject = subject;
message.Body = new TextPart("plain") { Text = body };
using (var client = new SmtpClient())
{
client.Connect(myConfig.GetHost(), myConfig.GetPort(), myConfig.GetUseSSL());
// Note: only needed if the SMTP server requires authentication
if (myConfig.GetToken() != "none")
{
client.Authenticate(myConfig.GetUser(), myConfig.GetToken());
}
client.Send(message);
client.Disconnect(true);
}
sent++;
return new KeyValuePair<bool, string>(true, "Sending");
}
catch (Exception ex)
{
LogFormater.Warn("Failed to send email: "+ex.Message);
failed++;
return new KeyValuePair<bool, string>(false, "Failed to send email: " + ex.Message);
}
}
protected void BotClientRestart(object o, BotClientNotice e)
{
if (e.isStart == false)
{
return;
}
botConnected = false;
LogFormater.Info("SMTP Service [Attached to new client]");
GetClient().Network.LoggedOut += BotLoggedOut;
GetClient().Network.SimConnected += BotLoggedIn;
GetClient().Self.AlertMessage += BotAlertMessage;
}
protected void BotLoggedOut(object o, LoggedOutEventArgs e)
{
botConnected = false;
LogFormater.Info("SMTP Service [Standby]");
}
protected void BotLoggedIn(object o, SimConnectedEventArgs e)
{
bool loginEvent = false;
if(botConnected == false)
{
loginEvent = true;
}
LogFormater.Info("SMTP Service [Active]");
botConnected = true;
if (loginEvent == true)
{
if (myConfig.GetAllowSendAlertStatus() == false)
{
return;
}
if (myConfig.GetSendAlertsAndLoginsTo() == "me@somewhere.tld")
{
return;
}
SendMail("Bot - Login message", GetClient().Self.Name + " has signed in", myConfig.GetSendAlertsAndLoginsTo());
}
}
public override void Start(bool updateEnabled = false, bool setEnabledTo = false)
{
if (updateEnabled)
{
myConfig.setEnabled(setEnabledTo);
}
if (myConfig.GetEnabled() == false)
{
return;
}
Stop();
running = true;
master.BotClientNoticeEvent += BotClientRestart;
LogFormater.Info("SMTP Service [Starting]");
}
public override void Stop()
{
if(running == true)
{
LogFormater.Info("SMTP Service [Stopping]");
}
running = false;
master.BotClientNoticeEvent -= BotClientRestart;
if (master.BotClient != null)
{
if (GetClient() != null)
{
GetClient().Network.SimConnected -= BotLoggedIn;
GetClient().Self.AlertMessage -= BotAlertMessage;
}
}
}
}
}