#!rsc by RouterOS
# RouterOS script: mod/notification-email
# Copyright (c) 2013-2023 Christian Hesse <mail@eworm.de>
# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md

:global FlushEmailQueue;
:global NotificationFunctions;
:global SendEMail;
:global SendEMail2;

# flush e-mail queue
:set FlushEmailQueue do={
  :global EmailQueue;

  :global EitherOr;
  :global IsDNSResolving;
  :global IsTimeSync;
  :global LogPrintExit2;

  :local AllDone true;
  :local QueueLen [ :len $EmailQueue ];
  :local Scheduler [ /system/scheduler/find where name=$0 ];
  
  :if ([ :len $Scheduler ] > 0 && [ /system/scheduler/get $Scheduler interval ] < 1m) do={
    /system/scheduler/set interval=1m comment="Doing initial checks..." $Scheduler;
  }

  :if ([ /tool/e-mail/get last-status ] = "in-progress") do={
    $LogPrintExit2 debug $0 ("Sending mail is currently in progress, not flushing.") false;
    :return false;
  }

  :if ([ $IsTimeSync ] = false) do={
    $LogPrintExit2 debug $0 ("Time is not synced, not flushing.") false;
    :return false;
  }

  :if ([ :typeof [ :toip [ /tool/e-mail/get address ] ] ] != "ip" && [ $IsDNSResolving ] = false) do={
    $LogPrintExit2 debug $0 ("Server address is a DNS name and resolving fails, not flushing.") false;
    :return false;
  }

  :if ([ :len $Scheduler ] > 0 && $QueueLen = 0) do={
    $LogPrintExit2 warning $0 ("Flushing E-Mail messages from scheduler, but queue is empty.") false;
  }

  /system/scheduler/set interval=([ $EitherOr $QueueLen 1 ] . "m") comment="Sending..." $Scheduler;

  :foreach Id,Message in=$EmailQueue do={
    :if ([ :typeof $Message ] = "array" ) do={
      :local Attach ({});
      :while ([ /tool/e-mail/get last-status ] = "in-progress") do={ :delay 1s; }
      :foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={
        :if ([ :len [ /file/find where name=$File ] ] = 1) do={
          :set Attach ($Attach, $File);
        } else={
          $LogPrintExit2 warning $0 ("File '" . $File . "' does not exist, can not attach.") false;
        }
      }
      /tool/e-mail/send to=($Message->"to") cc=($Message->"cc") subject=($Message->"subject") \
        body=($Message->"body") file=$Attach;
      :local Wait true;
      :do {
        :delay 1s;
        :local Status [ /tool/e-mail/get last-status ];
        :if ($Status = "succeeded") do={
          :set ($EmailQueue->$Id);
          :set Wait false;
          :if (($Message->"remove-attach") = true) do={
            :foreach File in=$Attach do={
              /file/remove $File;
            }
          }
        }
        :if ($Status = "failed") do={
          :set AllDone false;
          :set Wait false;
        }
      } while=($Wait = true);
    }
  }

  :if ($AllDone = true && $QueueLen = [ :len $EmailQueue ]) do={
    /system/scheduler/remove $Scheduler;
    :set EmailQueue;
  } else={
    /system/scheduler/set interval=1m comment="Waiting for retry..." $Scheduler;
  }
}

# send notification via e-mail - expects one array argument
:set ($NotificationFunctions->"email") do={
  :local Notification $1;

  :global Identity;
  :global EmailGeneralTo;
  :global EmailGeneralToOverride;
  :global EmailGeneralCc;
  :global EmailGeneralCcOverride;
  :global EmailQueue;

  :global EitherOr;
  :global IfThenElse;
  :global QuotedPrintable;

  :local To [ $EitherOr ($EmailGeneralToOverride->($Notification->"origin")) $EmailGeneralTo ];
  :local Cc [ $EitherOr ($EmailGeneralCcOverride->($Notification->"origin")) $EmailGeneralCc ];

  :local EMailSettings [ /tool/e-mail/get ];
  :if ([ :len $To ] = 0 || ($EMailSettings->"address") = "0.0.0.0" || ($EMailSettings->"from") = "<>") do={
    :return false;
  }

  :if ([ :typeof $EmailQueue ] = "nothing") do={
      :set EmailQueue ({});
  }
  :local Signature [ /system/note/get note ];
  :set ($EmailQueue->[ :len $EmailQueue ]) {
    to=$To; cc=$Cc;
    subject=[ $QuotedPrintable ("[" . $Identity . "] " . ($Notification->"subject")) ];
    body=(($Notification->"message") . \
      [ $IfThenElse ([ :len ($Notification->"link") ] > 0) ("\n\n" . ($Notification->"link")) "" ] . \
      [ $IfThenElse ([ :len $Signature ] > 0) ("\n-- \n" . $Signature) "" ]); \
    attach=($Notification->"attach"); remove-attach=($Notification->"remove-attach") };
  :if ([ :len [ /system/scheduler/find where name="\$FlushEmailQueue" ] ] = 0) do={
    /system/scheduler/add name="\$FlushEmailQueue" interval=1s start-time=startup \
      comment="Queuing new mail..." on-event=(":global FlushEmailQueue; \$FlushEmailQueue;");
  }
}

# send notification via e-mail - expects at least two string arguments
:set SendEMail do={
  :global SendEMail2;

  $SendEMail2 ({ subject=$1; message=$2; link=$3 });
}

# send notification via e-mail - expects one array argument
:set SendEMail2 do={
  :local Notification $1;

  :global NotificationFunctions;

  ($NotificationFunctions->"email") ("\$NotificationFunctions->\"email\"") $Notification;
}