Limit Outbound Mails by User, Domain or Server Average #2

This section contains scripts that hMailServer has contributed with. hMailServer 5 is needed to use these.
percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Limit Outbound Mails by User, Domain or Server Average #2

Post by percepts » 2013-07-19 01:47

Version #2.1

This script is an updated and modified version of Andyp's orginal version ( see topic: http://www.hmailserver.com/forum/viewto ... 20&t=13824)

This topic has been started to make this new version more easily accessible.

This script limits the outbound emails either by user account or by domain. It also calculates an average over the last x days and when the total amount of outbound emails reaches a defined level the mail is also blocked.

The primary reason for this script is the higher security. If one or some account gets hacked the damage is limited. And it allows the email administrator to limit abuse by valid users sending out mass mailings.

How does user or domain limits work?
You define a general user and domain limit. In a separate file you can also define exceptions for users or domain. The script counts every mail and if the amount reaches the limit a message will be send and the mail will be rejected. You can also define a warning level, when an email is send saying the limits will be reached soon. These mails can be send to the admin or the user.

How does server average limit work?
The script counts the outbound mail of the server and calculates an average over the last x days. When the server passes a threshold factor, let's say 5 times more than the average over the last 20 days the script rejects the mail. An email is send to the admin, also when a warning level is reached.

Note 1:
Since I didn't write the original script and haven't checked all logic in it, I assume it does what it's supposed to. It seems to work for my light testing. I just cleaned up some code and fixed a bug or two others had discovered.

Note 2:
Since this script uses filesystem to open, read, write, close upto 4 files for each email processed, it has the potential to slow down message processing. This may be significant on a busy server but apprently works fine for most people.
You have been warned.

Install instructions are in the zip file.

Good luck with it...

ttambellini
New user
New user
Posts: 22
Joined: 2013-07-14 19:03
Location: Pittsburgh, PA

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by ttambellini » 2013-07-19 02:20

One of my users had his credentials compromised and our server was sending thousands of spam messages over a long weekend. This caused pretty big problems, especially with sending to gmail addresses because of being blacklisted.

The boss was so angry he was suggesting we move to Exchange. Talk about solving a rodent problem with an atomic bomb!

Using this script now and confident we won't have this problem again. I have a few dozen users and a couple thousand emails a day max. It works well and with this low volume it doesn't appear to have any negative impact on performance.

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-07-19 14:16

One thing you should Know is that the script only sends messages to email admin when limit is exceeded and not when warning is sent to sender of approaching limit. i.e. email admin only gets notified at point when sender can no longer send emails.

ttambellini
New user
New user
Posts: 22
Joined: 2013-07-14 19:03
Location: Pittsburgh, PA

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by ttambellini » 2013-07-19 17:43

percepts wrote:One thing you should Know is that the script only sends messages to email admin when limit is exceeded and not when warning is sent to sender of approaching limit. i.e. email admin only gets notified at point when sender can no longer send emails.

To change this, and send the warning email to the administrator as well, change this subroutine as shown below, adding the section in bold:


Original:

Code: Select all

Sub outgoing_limitations_send_message(oClient, oMessage, iswarning, nr, max, isdomain)
	Dim txt
	Dim tmp
	Dim nMessage
	Dim strAccount
	
	tmp = oMessage.FromAddress
	
	If iswarning Then
		txt = "Hello " & tmp & nl & nl
		txt = txt & "you will soon reach your account limits." & nl & nl
		txt = txt & "Current amount is " & nr & nl
		txt = txt & "Limit is " & max & nl & nl
		If isdomain Then
			txt = txt & "This is a limit of the your domain." & nl & nl
		Else
			txt = txt & "This is a limit of the your account." & nl & nl
		End If
		txt = txt & "Regards" & nl
		txt = txt & msg_AdminEmail
		
		strAccount = split(tmp, "@")

		Set nMessage = CreateObject("hMailServer.Message")
		nMessage.From = msg_AdminEmail
		nMessage.FromAddress = msg_AdminName & " <" & msg_AdminEmail & ">"
		nMessage.AddRecipient strAccount(0), tmp
		nMessage.Subject = "Warning: Account limits will be reached soon"
		nMessage.Body = txt
		nMessage.Save
	Else
		txt = "Hello " & tmp & nl & nl
		txt = txt & "you have passed your account limits." & nl & nl
		txt = txt & "Current amount is " & nr & nl
		txt = txt & "Limit is " & max & nl & nl
		If isdomain Then
			txt = txt & "This is a limit of the your domain." & nl & nl
		Else
			txt = txt & "This is a limit of the your account." & nl & nl
		End If
		txt = txt & "Regards" & nl
		txt = txt & msg_AdminEmail
		
		Set nMessage = CreateObject("hMailServer.Message")
		nMessage.From = msg_AdminEmail
		nMessage.FromAddress = msg_AdminName & " <" & msg_AdminEmail & ">"
		nMessage.AddRecipient msg_AdminName, msg_AdminEmail
		nMessage.Subject = "Locked: Account limits passed"
		nMessage.Body = txt
		nMessage.Save

		strAccount = split(tmp, "@")
		
		Set nMessage = CreateObject("hMailServer.Message")
		nMessage.From = msg_AdminEmail
		nMessage.FromAddress = msg_AdminName & " <" & msg_AdminEmail & ">"
		nMessage.AddRecipient strAccount(0), tmp
		nMessage.Subject = "Locked: Account limits passed"
		nMessage.Body = txt
		nMessage.Save
	End If
End Sub


Edited:

Code: Select all

Sub outgoing_limitations_send_message(oClient, oMessage, iswarning, nr, max, isdomain)
	Dim txt
	Dim tmp
	Dim nMessage
	Dim strAccount
	
	tmp = oMessage.FromAddress
	
	If iswarning Then
		txt = "Hello " & tmp & nl & nl
		txt = txt & "you will soon reach your account limits." & nl & nl
		txt = txt & "Current amount is " & nr & nl
		txt = txt & "Limit is " & max & nl & nl
		If isdomain Then
			txt = txt & "This is a limit of your domain." & nl & nl
		Else
			txt = txt & "This is a limit of your account." & nl & nl
		End If
		txt = txt & "Regards" & nl
		txt = txt & msg_AdminName

[b]		Set nMessage = CreateObject("hMailServer.Message")
		nMessage.From = msg_AdminEmail
		nMessage.FromAddress = msg_AdminName & " <" & msg_AdminEmail & ">"
		nMessage.AddRecipient msg_AdminName, msg_AdminEmail
		nMessage.Subject = "Warning: Account limits will be reached soon"
		nMessage.Body = txt
		nMessage.Save[/b]
		
		strAccount = split(tmp, "@")

		Set nMessage = CreateObject("hMailServer.Message")
		nMessage.From = msg_AdminEmail
		nMessage.FromAddress = msg_AdminName & " <" & msg_AdminEmail & ">"
		nMessage.AddRecipient strAccount(0), tmp
		nMessage.Subject = "Warning: Account limits will be reached soon"
		nMessage.Body = txt
		nMessage.Save
	Else
		txt = "Hello " & tmp & nl & nl
		txt = txt & "you have passed your account limits." & nl & nl
		txt = txt & "Current amount is " & nr & nl
		txt = txt & "Limit is " & max & nl & nl
		If isdomain Then
			txt = txt & "This is a limit of your domain." & nl & nl
		Else
			txt = txt & "This is a limit of your account." & nl & nl
		End If
		txt = txt & "Regards" & nl
		txt = txt & msg_AdminName
		
		Set nMessage = CreateObject("hMailServer.Message")
		nMessage.From = msg_AdminEmail
		nMessage.FromAddress = msg_AdminName & " <" & msg_AdminEmail & ">"
		nMessage.AddRecipient msg_AdminName, msg_AdminEmail
		nMessage.Subject = "Locked: Account limits passed"
		nMessage.Body = txt
		nMessage.Save

		strAccount = split(tmp, "@")
		
		Set nMessage = CreateObject("hMailServer.Message")
		nMessage.From = msg_AdminEmail
		nMessage.FromAddress = msg_AdminName & " <" & msg_AdminEmail & ">"
		nMessage.AddRecipient strAccount(0), tmp
		nMessage.Subject = "Locked: Account limits passed"
		nMessage.Body = txt
		nMessage.Save
	End If
End Sub

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-07-19 18:53

Looks good. You are now an expert VBS programmer :)

ttambellini
New user
New user
Posts: 22
Joined: 2013-07-14 19:03
Location: Pittsburgh, PA

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by ttambellini » 2013-07-19 19:24

percepts wrote:Looks good. You are now an expert VBS programmer :)
Far from an expert!

"One who wants to, finds a way; one who doesn't, finds an excuse." - Ron Martin

I simply chose to find a way.

This is one of the wonderful things about hMailServer... It allows us to use scripts like this to do almost anything we may want to do. It's just a matter of finding a way.

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-07-22 17:36

Version #2.1
Version #2.2 - Fix to put to put From and FromAddress the right way round and to preserve user name where it exists

This script is an updated and modified version of Andyp's orginal version ( see topic: http://www.hmailserver.com/forum/viewto ... 20&t=13824)

This topic has been started to make this new version more easily accessible.

This script limits the outbound emails either by user account or by domain. It also calculates an average over the last x days and when the total amount of outbound emails reaches a defined level the mail is also blocked.

The primary reason for this script is the higher security. If one or some account gets hacked the damage is limited. And it allows the email administrator to limit abuse by valid users sending out mass mailings.

How does user or domain limits work?
You define a general user and domain limit. In a separate file you can also define exceptions for users or domain. The script counts every mail and if the amount reaches the limit a message will be send and the mail will be rejected. You can also define a warning level, when an email is send saying the limits will be reached soon. These mails can be send to the admin or the user.

How does server average limit work?
The script counts the outbound mail of the server and calculates an average over the last x days. When the server passes a threshold factor, let's say 5 times more than the average over the last 20 days the script rejects the mail. An email is send to the admin, also when a warning level is reached.

Note 1:
Since I didn't write the original script and haven't checked all logic in it, I assume it does what it's supposed to. It seems to work for my light testing. I just cleaned up some code and fixed a bug or two others had discovered.

Note 2:
Since this script uses filesystem to open, read, write, close upto 4 files for each email processed, it has the potential to slow down message processing. This may be significant on a busy server but apprently works fine for most people.
You have been warned.

Install instructions are in the zip file.

Good luck with it...

meratigoerr
New user
New user
Posts: 2
Joined: 2013-07-29 19:31

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by meratigoerr » 2013-07-30 13:27

My scripting is very limited, but this looks like exactly what i'm looking for - minus one thing. Is it possible to modify the script to restrict sending mail from only one or two domains?

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-07-31 18:13

script already has ability to limit specific accounts and/or domains to a max limit of outbound emails

Install script and send an email from yourself to yourself. Then look in events folder where count files are created. You can edit the outboundexceptions.txt file to set a limit on any user and/or domain outbound. You just need to add all the domains you want to limit to 0 outbound emails. Example of how to do it is in the file.

jrclark
New user
New user
Posts: 10
Joined: 2012-05-25 04:40
Location: Minnesota

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by jrclark » 2013-08-27 19:03

In:

Function is_local_domain(domain_or_email)

Need:

Dim dom
Dim als

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-08-27 20:00

jrclark wrote:In:

Function is_local_domain(domain_or_email)

Need:

Dim dom
Dim als
yes it would appear so. I didn't get failure though and I had option explicit on I think so not sure how that worked.

agserna
Normal user
Normal user
Posts: 69
Joined: 2011-10-05 23:43

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by agserna » 2013-09-09 11:18

Hy Percepts.

Using script v 2.2

If i send a message (via client) to multiple recipients (to: mailaddress1; mailaddress2; mailaddress3; mailaddress4...) the counter in outboundstore.txt indicates 1 mail sent.

The server which i use to test the script has about 100 domains and 500 accounts, so i don't know if this is due to server load or script bug. Can somebody try to test this?

Many thanks.

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-09-09 13:03

Limiting is based on the number of recipients. However, it does not count messages sent to the sender. So if you only used two recipients in test and one was yourself then you would only see 1 in the count. Test using 3 or 4 recipients and you'll see what I mean.

agserna
Normal user
Normal user
Posts: 69
Joined: 2011-10-05 23:43

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by agserna » 2013-09-09 16:35

Hi and thanks for reply.

In my test none of the recipients was the same as sender. I sent message from my personal domain to following test recipients: hotmail, gmail, aol, yahoo, live, libero.

All of the recipients where put in "To" field (no bcc, no cc) separated by semicolon. All emails sent were regularly received by each test account but the counter in outboundstore.txt was 1 not 6 as espected.

Any idea?

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-09-09 17:12

Don't know because it works for me.

Which version are you running? Should be this one:

http://www.hmailserver.com/forum/viewto ... 44#p152080

And have you made any changes to code and if so did you reload scripts?

And in your logs folder are there any error logs with script errors?

User avatar
mattg
Moderator
Moderator
Posts: 20632
Joined: 2007-06-14 05:12
Location: 'The Outback' Australia

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by mattg » 2013-09-09 17:17

Which Mail client people?
Some mail clients treat things like semi-colons differently
Just 'cause I link to a page and say little else doesn't mean I am not being nice.
https://www.hmailserver.com/documentation

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-09-09 17:30

the code just takes oMessage.Recipients.Count so assuming hMail is working properly which it is if all of them got their email, then the address separator shouldn't be the problem(I think)

Was the sender a local domain? i.e. one setup in hmail ?

hytanium
New user
New user
Posts: 24
Joined: 2007-11-12 05:21

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by hytanium » 2013-09-10 22:31

Just curious,

Does the email limit reset at the end of the day automatically?? Or is that what the scheduled task is for??

We just turned on the script...and it is working well. We host almost 5000 addys and have been hit with comprimised email accounts over the past few weeks...this will stop the stress.. I'm sure.

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-09-10 22:55

the cycleeventlog script just resets the log file. It has no effect on email limits. That is taken care of by the main script according to the settings you use.

hytanium
New user
New user
Posts: 24
Joined: 2007-11-12 05:21

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by hytanium » 2013-09-10 23:52

OK, thanks.

agserna
Normal user
Normal user
Posts: 69
Joined: 2011-10-05 23:43

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by agserna » 2013-09-12 08:44

Hi.

Script version is 2.2

The test was performet using MS OFFICE OUTLOOK 2003.

No changes made in code.

Variables settings:

'General
Public obApp
Public domain_buffer
Public Const ipslocalhost = "94.23.xxx.xxx#178.32.xxx.xxx" 'separated by #
Public Const user = "username"
Public Const pw = "password" ' ## enter your hmail admin password here

Public Const write_log_active = False

'User and Domain outgoing limitation
Public Const outgoingstore = "my path"
Public Const outgoingexceptions = "my path"
Public Const outgoingstoreavg = "my path"
Public Const max_emails_per_user = 100
Public Const max_emails_per_domain = 1000
Public Const warning_factor = 0.8
Public Const server_average_days = 0 ' 0 will deactivate
Public Const server_average_threshold_factor = 10
Public Const warning_factor_avg = 0.6
Public Const msg_AdminName = """Email Admin""" ' ## enter name here. N.B. leave """ as is.
Public Const msg_AdminEmail = "admin@mypersonaldomain.com" ' ## enter your email admin email address here

Also: Emails body has a simple "Hello", HTML format, no attachments.

Bye

agserna
Normal user
Normal user
Posts: 69
Joined: 2011-10-05 23:43

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by agserna » 2013-09-12 10:18

After 3 more tests: (sender, recipients, mail body and so on are always as indicated previously)

Can confirm that the problem occurs randomly.

In test #1 the account counter is 1, in test #2 the account counter is 2 and in test #3 the account counter is 6. The domain counter is OK: 6 in each test.

If somebody is testing, please keep in mynd that the sender domain has many accounts (even though all tests are performed with the same one).

Thanks again for support.

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-09-12 12:09

please post your full eventhandlers.vbs file

NOT edited down, but everything. (except you can obfuscate your password)

agserna
Normal user
Normal user
Posts: 69
Joined: 2011-10-05 23:43

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by agserna » 2013-09-12 18:15

Here it is the whole text in eventhandler...

' Sub OnClientConnect(oClient)
' End Sub

' Sub OnAcceptMessage(oClient, oMessage)
' End Sub

' Sub OnDeliveryStart(oMessage)
' End Sub

' Sub OnDeliverMessage(oMessage)
' End Sub

' Sub OnBackupFailed(sReason)
' End Sub

' Sub OnBackupCompleted()
' End Sub

' Sub OnError(iSeverity, iCode, sSource, sDescription)
' End Sub

' Sub OnDeliveryFailed(oMessage, sRecipient, sErrorMessage)
' End Sub

' Sub OnExternalAccountDownload(oMessage, sRemoteUID)
' End Sub


'Force error on undeclared variables
Option Explicit

'------------------------------------------------------------------
' SMTP Limit - Global variables and settings
'------------------------------------------------------------------

'General
Public obApp
Public domain_buffer
Public Const ipslocalhost = "94.23.xxx.xxx#178.32.xxx.xxx" 'separated by #
Public Const user = "username"
Public Const pw = "password" ' ## enter your hmail admin password here

Public Const write_log_active = False

'User and Domain outgoing limitation
Public Const outgoingstore = "my path"
Public Const outgoingexceptions = "my path"
Public Const outgoingstoreavg = "my path"
Public Const max_emails_per_user = 100
Public Const max_emails_per_domain = 1000
Public Const warning_factor = 0.8
Public Const server_average_days = 0 ' 0 will deactivate
Public Const server_average_threshold_factor = 10
Public Const warning_factor_avg = 0.6
Public Const msg_AdminName = """Email Admin""" ' ## enter name here. N.B. leave """ as is.
Public Const msg_AdminEmail = "mailadmin@mydomain.com" ' ## enter your email admin email address here



Sub OnAcceptMessage(oClient, oMessage)
Result.Value = 0
Set obApp = CreateObject("hMailServer.Application")
Call obApp.Authenticate(user, pw)

If has_client_authenticated(oClient) Then
write_log (" User has authenticated. User " & oCLient.username & ", Client " & oClient.IPAddress)
if not check_outgoing_limitations(oClient, oMessage) Then
Result.Message = "Your account/Mailserver has passed SMTP outgoing limits."
Result.Value = 2
End if
End if
End Sub

'------------------------------------------------------------------
' SMTP Limit - Functions and Subs for outgoing emails of domain and user
'------------------------------------------------------------------

function check_outgoing_limitations(oClient, oMessage)
check_outgoing_limitations = true
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Dim fs , f
Set fs = CreateObject("scripting.filesystemobject")
Dim idt
Dim content
Dim ln
Dim arr
Dim usern
Dim usernadd
Dim usernnr
Dim usernnrmax
Dim domn
Dim domnadd
Dim domnnr
Dim domnnrmax
Dim reason
Dim rcptscnt
Dim dayamounts(200)
Dim i, k

For i = 0 To 200
dayamounts(i) = 0
Next
Dim pos
Dim avg
Dim minday
minday = 999999
Dim toindex
Dim excptn

write_log(" SMTP outgoing limitations")

If oclient.username <> "" Then
If instr(1,oclient.username,"@") = 0 Then
usern = oclient.username & "@" & obApp.Settings.DefaultDomain
domn = "@" & obApp.Settings.DefaultDomain
Else
usern = oclient.username
domn = Mid(oclient.username,InStr(1,oclient.username,"@"))
End If
ElseIf is_local_domain(omessage.fromaddress) then
usern = omessage.fromaddress
domn = Mid(omessage.fromaddress,InStr(1,omessage.fromaddress,"@"))
Else
usern = "local"
domn = "@local"
End If
content = "# SMTP outgoing storage" & nl & nl
usernadd = true
domnadd = true
usernnr = 1
domnnr = 1
usernnrmax = max_emails_per_user
domnnrmax = max_emails_per_domain
idt = CLng(Date())
rcptscnt = omessage.Recipients.count
write_log(" Number of recipients " & rcptscnt)

write_log(" Reading exceptions file " & outgoingexceptions)
If fs.FileExists(outgoingexceptions) Then
Set f = fs.OpenTextFile(outgoingexceptions, ForReading)
Do While Not f.AtEndOfStream
ln = f.ReadLine
If ln <> "" And Mid(ln,1,1) <> "#" And Len(ln) > 3 Then
arr = Split(ln,Chr(9))
If UBound(arr) = 1 Then
If arr(0) = usern Then
usernnrmax = CLng(arr(1))
write_log (" new user limit " & ln)
End if
If arr(0) = domn Then
domnnrmax = CLng(arr(1))
write_log (" new domain limit " & ln)
End if
Else
write_log (" cannot process line " & Mid(ln,1,25))
End If
ElseIf Len(ln) > 5 And f.Line > 4 + 1 then
write_log (" skipping line " & Mid(ln,1,25))
End If
Loop
Else
Set f = fs.OpenTextFile(outgoingexceptions, ForWriting, true)
f.Write("# Outgoing limitation exceptions tab / chr(9) separated" & nl)
f.Write("# Examples (without # at the beginning)" & nl)
f.Write("# @yourdomain.com 10000" & nl)
f.Write("# address@yourdomain.com 5000" & nl & nl)
f.Close
End If

write_log(" Reading storage file " & outgoingstore)
If fs.FileExists(outgoingstore) Then
Set f = fs.OpenTextFile(outgoingstore, ForReading)
Do While Not f.AtEndOfStream
ln = f.ReadLine
If ln <> "" And Mid(ln,1,1) <> "#" And Len(ln) > 5 Then
arr = Split(ln," ")
If UBound(arr) > 1 Then
If minday > CLng(arr(0)) Then
minday = CLng(arr(0))
End If
End If
If UBound(arr) = 2 Or UBound(arr) = 3 Then
If CLng(arr(0)) = idt And arr(2) = usern Then
usernnr = CLng(arr(1)) + rcptscnt
usernadd = False
write_log (" adding to line " & ln)
If usernnr > usernnrmax Then
If UBound(arr) = 3 Then
If arr(3) = "X" then
write_log (" deny already sent")
Else
write_log (" sending deny")
outgoing_limitations_send_message oClient, oMessage, false, usernnr, usernnrmax, false
End if
Else
write_log (" sending deny")
outgoing_limitations_send_message oClient, oMessage, false, usernnr, usernnrmax, false
End If
content = content & arr(0) & " " & usernnr & " " & arr(2) & " X" & nl
ElseIf usernnr > usernnrmax * warning_factor then
If UBound(arr) = 3 Then
If arr(3) = "W" then
write_log (" warning already sent")
Else
write_log (" sending warning")
outgoing_limitations_send_message oClient, oMessage, true, usernnr, usernnrmax, false
End if
Else
write_log (" sending warning")
outgoing_limitations_send_message oClient, oMessage, true, usernnr, usernnrmax, false
End If
content = content & arr(0) & " " & usernnr & " " & arr(2) & " W" & nl
Else
content = content & arr(0) & " " & usernnr & " " & arr(2) & nl
End if
elseIf CLng(arr(0)) = idt And arr(2) = domn Then
domnnr = CLng(arr(1)) + rcptscnt
domnadd = false
write_log (" adding to line " & ln)
If domnnr > domnnrmax Then
If UBound(arr) = 3 Then
If arr(3) = "X" then
write_log (" deny already sent")
Else
write_log (" sending deny")
outgoing_limitations_send_message oClient, oMessage, false, domnnr, domnnrmax, true
End if
Else
write_log (" sending deny")
outgoing_limitations_send_message oClient, oMessage, false, domnnr, domnnrmax, true
End If
content = content & arr(0) & " " & domnnr & " " & arr(2) & " X" & nl
ElseIf domnnr > domnnrmax * warning_factor then
If UBound(arr) = 3 Then
If arr(3) = "W" then
write_log (" warning already sent")
Else
write_log (" sending warning")
outgoing_limitations_send_message oClient, oMessage, true, domnnr, domnnrmax, true
End if
Else
write_log (" sending warning")
outgoing_limitations_send_message oClient, oMessage, true, domnnr, domnnrmax, true
End If
content = content & arr(0) & " " & domnnr & " " & arr(2) & " W" & nl
Else
content = content & arr(0) & " " & domnnr & " " & arr(2) & nl
End if
ElseIf CLng(arr(0)) < idt - server_average_days Then
write_log (" deleting line " & ln)
Else
content = content & arr(0) & " " & arr(1) & " " & arr(2) & nl
'write_log (" copying line " & ln)
End If
If Mid(arr(2),1,1) <> "@" Then
pos = idt - CLng(arr(0))
dayamounts(pos) = dayamounts(pos) + CLng(arr(1))
End If
Else
write_log (" cannot process line " & Mid(ln,1,25))
End If
ElseIf Len(ln) > 5 And f.Line > 1 + 1 then
write_log (" skipping line " & Mid(ln,1,25))
End If
Loop
f.Close
If usernadd Then
content = content & idt & " " & usernnr & " " & usern & nl
End If
If domnadd Then
content = content & idt & " " & domnnr & " " & domn & nl
End If
Set f = fs.OpenTextFile(outgoingstore, ForWriting, true)
f.Write(content)
f.Close
Else
content = content & idt & " " & usernnr & " " & usern & nl
content = content & idt & " " & domnnr & " " & domn & nl
Set f = fs.OpenTextFile(outgoingstore, ForWriting, true)
f.Write(content)
f.Close
End If

toindex = idt - minday
avg = CDbl(0)
If toindex >=5 then
For i = 1 To toindex
avg = avg + CDbl(dayamounts(i))
Next
avg = CDbl(avg) / CDbl(toindex)
write_log(" Statistic calculation over " & server_average_days & " days")
write_log(" todays amount " & dayamounts(0) & " average " & avg & " maximum " & avg * server_average_threshold_factor)
write_log(" Checking statistics")
End If
If toindex < 5 then
write_log(" Statistic calculation is only done over at least 5 days. Available days: " & toindex)
ElseIf avg < 5 Then
write_log(" average below 5 mails per day, ignoring average statistic")
ElseIf dayamounts(0) > avg * server_average_threshold_factor Then
write_log(" todays amount has passed limit of " & avg * server_average_threshold_factor)
outgoing_limitations_avg_send_admin dayamounts(0),avg * server_average_threshold_factor,false
check_outgoing_limitations = False
ElseIf dayamounts(0) > avg * server_average_threshold_factor * warning_factor_avg Then
write_log(" todays amount has passed warning level of " & avg * server_average_threshold_factor * warning_factor_avg)
outgoing_limitations_avg_send_admin dayamounts(0),avg * server_average_threshold_factor,true
check_outgoing_limitations = False
Else
write_log(" within limits")
End If

write_log(" Checking limits")
If usernnrmax < usernnr Then
check_outgoing_limitations = false
write_log(" max of user passed!")
ElseIf domnnrmax < domnnr Then
check_outgoing_limitations = false
write_log(" max of domain passed!")
Else
write_log(" within limits")
End If

excptn = false
If oMessage.FromAddress = msg_AdminEmail Then
excptn = true
Else
For k = 0 To oMessage.recipients.count - 1
If oMessage.recipients(k).OriginalAddress = msg_AdminEmail Then
excptn = True
End If
Next
End If
If excptn = True Then
write_log(" Mail from/to admin -> passes lock")
check_outgoing_limitations = true
End if
End function

Sub outgoing_limitations_avg_send_admin(nr, max, iswarning)
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Dim fs , f
Set fs = CreateObject("scripting.filesystemobject")
Dim txt
Dim tmp
Dim str
Dim out
Dim snd

If iswarning Then
tmp = "Warning: Todays outgoing emails will reach lock soon"

txt = "Hello " & msg_AdminEmail & nl & nl
txt = txt & "todays outgoing email will reach avg limit soon." & nl & nl
txt = txt & "Current amount is " & nr & nl
txt = txt & "Limit is " & max & nl & nl
txt = txt & "Regards" & nl
txt = txt & msg_AdminEmail

str = "W" & CLng(Date())
Else
tmp = "Locked: Todays outgoing emails have passed avg limit"

txt = "Hello " & msg_AdminEmail & nl & nl
txt = txt & "todays outgoing email have passed avg limit." & nl & nl
txt = txt & "Current amount is " & nr & nl
txt = txt & "Limit is " & max & nl & nl
txt = txt & "Regards" & nl
txt = txt & msg_AdminEmail

str = "X" & CLng(Date())
End If

snd = true
If fs.FileExists(outgoingstoreavg) Then
Set f = fs.OpenTextFile(outgoingstoreavg,ForReading)
out = f.ReadAll
f.Close
If out = str Then
snd = false
End If
End If

If snd then
Set nMessage = CreateObject("hMailServer.Message")
nMessage.From = msg_AdminName & " <" & msg_AdminEmail & ">"
nMessage.FromAddress = msg_AdminEmail
nMessage.AddRecipient msg_AdminName, msg_AdminEmail
nMessage.Subject = tmp
nMessage.Body = txt
nMessage.Save

Set f = fs.OpenTextFile(outgoingstoreavg,ForWriting,True)
f.Write(str)
f.Close
End If
End Sub

Sub outgoing_limitations_send_message(oClient, oMessage, iswarning, nr, max, isdomain)
Dim txt
Dim tmp
Dim nMessage
Dim strAccount
Dim strFromName
Dim strFromAddress

tmp = oMessage.From

if (InStr(1, oMessage.From, "<", 1) > 0) Then
strAccount = split(oMessage.From, "<")
strFromAddress = Replace(strAccount(1), ">", "")
strFromName = Trim(strAccount(0))
strFromName = Replace (strFromName, """", "")
Else
strFromAddress = oMessage.From
strAccount = split(oMessage.From, "@")
strFromName = strAccount(0)
End If

If iswarning Then
txt = "Hello " & tmp & nl & nl
txt = txt & "you will soon reach your account limits." & nl & nl
txt = txt & "Current amount is " & nr & nl
txt = txt & "Limit is " & max & nl & nl
If isdomain Then
txt = txt & "This is a limit of the your domain." & nl & nl
Else
txt = txt & "This is a limit of the your account." & nl & nl
End If
txt = txt & "Regards" & nl
txt = txt & msg_AdminEmail

Set nMessage = CreateObject("hMailServer.Message")
nMessage.From = msg_AdminName & " <" & msg_AdminEmail & ">"
nMessage.FromAddress = msg_AdminEmail
nMessage.AddRecipient msg_AdminName, msg_AdminEmail
nMessage.Subject = "Warning: Account limits will be reached soon"
nMessage.Body = txt
nMessage.Save

Set nMessage = CreateObject("hMailServer.Message")
nMessage.From = msg_AdminName & " <" & msg_AdminEmail & ">"
nMessage.FromAddress = msg_AdminEmail
nMessage.AddRecipient strFromName, strFromAddress
nMessage.Subject = "Warning: Account limits will be reached soon"
nMessage.Body = txt
nMessage.Save
Else
txt = "Hello " & tmp & nl & nl
txt = txt & "you have passed your account limits." & nl & nl
txt = txt & "Current amount is " & nr & nl
txt = txt & "Limit is " & max & nl & nl
If isdomain Then
txt = txt & "This is a limit of the your domain." & nl & nl
Else
txt = txt & "This is a limit of the your account." & nl & nl
End If
txt = txt & "Regards" & nl
txt = txt & msg_AdminEmail

Set nMessage = CreateObject("hMailServer.Message")
nMessage.From = msg_AdminName & " <" & msg_AdminEmail & ">"
nMessage.FromAddress = msg_AdminEmail
nMessage.AddRecipient msg_AdminName, msg_AdminEmail
nMessage.Subject = "Locked: Account limits passed"
nMessage.Body = txt
nMessage.Save

Set nMessage = CreateObject("hMailServer.Message")
nMessage.From = msg_AdminName & " <" & msg_AdminEmail & ">"
nMessage.FromAddress = msg_AdminEmail
nMessage.AddRecipient strFromName, strFromAddress
nMessage.Subject = "Locked: Account limits passed"
nMessage.Body = txt
nMessage.Save
End If
End Sub

'------------------------------------------------------------------
' General functions of all scripts
'------------------------------------------------------------------

Sub write_log(txt)
If write_log_active then
EventLog.Write("Limit SMTP Script:"+txt)
End if
End Sub

Function get_date
Dim tmp
Dim erg
tmp = Year(Date)
erg = CStr(tmp)

If Month(Date) < 10 Then
tmp = "0" & Month(Date)
Else
tmp = Month(Date)
End If
erg = erg & "-" & tmp

If day(Date) < 10 Then
tmp = "0" & day(Date)
Else
tmp = day(Date)
End If
erg = erg & "-" & tmp

get_date = erg
End Function

Function nl
nl = Chr(13) & Chr(10)
End function

Function is_local_domain(domain_or_email)
is_local_domain = False
Dim domain
Dim doms
Dim alss
Dim i
Dim j

If InStr(1," " & domain_or_email,"@") > 0 Then
domain = Mid(domain_or_email, InStr(1,domain_or_email,"@") + 1)
Else
domain = domain_or_email
End If

If domain_buffer = "" then
i = 0
Set doms = obapp.Domains
Do While i <= doms.Count - 1
Set dom = doms.Item(i)
domain_buffer = domain_buffer & "#" & dom.Name
j = 0
Set alss = dom.DomainAliases
Do While j <= alss.Count - 1
Set als = alss.item(j)
domain_buffer = domain_buffer & "#" & als.AliasName
j = j + 1
Loop
i = i + 1
Loop
End If

If InStr(1, " " & domain_buffer, domain) > 0 Then
is_local_domain = True
End If
End Function

Function has_client_authenticated(oclient)
has_client_authenticated = false
If oCLient.username <> "" Or InStr(1," " & ipslocalhost, oClient.IPAddress) > 0 Then
has_client_authenticated = true
End if
End Function

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-09-12 20:46

that looks OK as far as I can tell. I didn't write this script so don't know its functionality in detail.
Without being able to replicate the error in my copy which adds correctly the only way you can work out whats going on is to put some extra logging to trace whats happening.

you can set "txt" to any values you like and call write_log(txt) which will log the value for you in the event log.
By doing that you should be able to see how those email addresses are actually being processed that you would expect them to be added into the counts.

hytanium
New user
New user
Posts: 24
Joined: 2007-11-12 05:21

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by hytanium » 2013-09-13 12:14

This script has been incredible for us so far. We have caught compromised email accounts in 3 separate occasions already.

Just wondering if there is a way we can limit the number of times an administrator is emailed once the account has passed the limit?

We get an email over and over again that looks like:

Hello "XXXl" <XXX@XXXl.com>

you have passed your account limits.

Current amount is 625
Limit is 100

This is a limit of the your account.

Regards
XXX@XXX.com

Otherwise...we are thrilled with the results. Thanks to the everyone who has contributed.

stephenlwells
New user
New user
Posts: 4
Joined: 2013-04-24 00:58

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by stephenlwells » 2013-09-20 19:19

Im having issues with it ignoring the exceptions not sure what im doing wrong everything else is working great any ideas?

my exceptions looks like this

# Outgoing limitation exceptions tab / chr(9) separated
# Examples (without # at the beginning)
# @yourdomain.com 10000
domain@domain.com 500
domain1@domain1.com 2000


i changed the domain name for privacy reasons but you get the idea am i missing something?

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-09-20 20:44

have you read what the first line of the exceptions file says? And have you followed the very clear instructions?

stephenlwells
New user
New user
Posts: 4
Joined: 2013-04-24 00:58

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by stephenlwells » 2013-09-23 18:01

yes i actually copied the example and just changed to domain to make sure. still not working... can post more info logs... whatever you need

thanks for the help.

molni
Normal user
Normal user
Posts: 31
Joined: 2005-08-25 12:47
Location: Hungary
Contact:

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by molni » 2013-11-06 02:07

Great script! :D

Keep up the good work!

chrigiboy
Normal user
Normal user
Posts: 31
Joined: 2007-11-08 14:52

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by chrigiboy » 2013-11-15 11:55

Hi, got just one little question:
Change this line in the manual:
1. Activate scripting in hmailserver: hm admin tool, settings->advanced->settings
1. Activate scripting in hmailserver: hm admin tool, settings->advanced->scripts



Are this settings per hour, day, week? I would like to use it as per hour:
Public Const max_emails_per_user = 100
Public Const max_emails_per_domain = 1000

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-11-15 12:00

I forget, I didn't write it. Suggest you read what it says in the manual and in the script itself. You never know it might be obvious if you actually look at it.

chrigiboy
Normal user
Normal user
Posts: 31
Joined: 2007-11-08 14:52

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by chrigiboy » 2013-11-15 12:10

No problem. I like the script ;-)
But what is about my question? Are the settings per hour, daily or weekly? Should i create a cronjob which drops the outboundstore.txt every hour?

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-11-15 12:12

Again
percepts wrote:I forget, I didn't write it. Suggest you read what it says in the manual and in the script itself. You never know it might be obvious if you actually look at it.

chrigiboy
Normal user
Normal user
Posts: 31
Joined: 2007-11-08 14:52

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by chrigiboy » 2013-11-15 12:18

Found it. In the original script it is daily. I will test it. Maybe i will change it to a higher rate. Because 100 mails per day and user is not much.

chrigiboy
Normal user
Normal user
Posts: 31
Joined: 2007-11-08 14:52

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by chrigiboy » 2013-11-19 18:07

Hello,
why you need ipslocalhost? I checked the script, they just check if the sender is authenticated. But why it is important? I want to count all emails, also the mails which are not authenticated (example: mails from the local webserver). I mean, the script should count all emails, from all ips even when the mail come from localhost. What should i have to change, so it will work?
Should i change this lines:
If has_client_authenticated(oClient) Then
write_log (" User has authenticated. User " & oCLient.username & ", Client " & oClient.IPAddress)
if not check_outgoing_limitations(oClient, oMessage) Then
Result.Message = "Your account/Mailserver has passed SMTP outgoing limits."
Result.Value = 2
End if
End if

New one:
check_outgoing_limitations(oClient, oMessage)
Result.Message = "Your account/Mailserver has passed SMTP outgoing limits."
Result.Value = 2

I think, with this change, hmailserver count also the incoming mailserver. i think that's not bad too.

c0r2ar0
New user
New user
Posts: 27
Joined: 2007-06-12 16:46
Location: Italy

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by c0r2ar0 » 2013-11-27 09:22

Hello there to everyone,
thanks for doing this nice and useful script!

We're using version 2.2

We're using it for about one year but in the last few months we're starting having a lot of users that they got they email password stolen by some sort of virus, their mailbox got hijacked and then some "nice people" start sending spam from all around the world with that account.

We've started getting an hourly report of outboundstore.txt but in this way after midday we've a lot of rows to monitor in the file and it's not possible to go ahead like this.

I'd like to know if there's a way to receive an email when some user bypass warning level. By now I've tried it but it sends a warning email to the user itself and not to the admin! In also when a user hit the sending limit I don't receive the alert email.

I'm obviously the admin and we host about 200 domains with about 10 mailboxes each.

The first part of our EventHandlers.vbs is:

Code: Select all

'------------------------------------------------------------------
' Global variables and settings
'------------------------------------------------------------------

'General
Public obApp
Public domain_buffer
Public Const ipslocalhost = "127.0.0.1"  'separated by #
Public Const user = "Administrator"
Public Const pw = "our password"
Public Const logspath = "d:\hMailServer\Logs\"   'ends with a backslash
Public Const write_log_active = true

'User and Domain outgoing limitation
Public Const outgoingstore = "d:\hMailServer\Events\outboundstore.txt"
Public Const outgoingexceptions = "d:\hMailServer\Events\outboundexceptions.txt"
Public Const outgoingstoreavg = "d:\hMailServer\Events\outboundstoreavg.txt"
Public Const max_emails_per_user = 2000
Public Const max_emails_per_domain = 4000
Public Const warning_factor = 0.9
Public Const server_average_days = 0     ' 0 will deactivate
Public Const server_average_threshold_factor = 1
Public Const warning_factor_avg = 0.9
Public Const msg_admin_warning = True
Public Const msg_admin_passed = True
Public Const msg_user_warning = False
Public Const msg_user_passed = False
Public Const msg_from = """<my email@my domain>"""
Public Const msg_fromaddress = "my email@my domain"

Can someone help us? I'm not very good at scripting at all.

Thanks in advance for reply.

Have a nice day!
Paolo

chrigiboy
Normal user
Normal user
Posts: 31
Joined: 2007-11-08 14:52

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by chrigiboy » 2013-12-05 11:47

Hello,
we're using 2.2 too. We get the email when someone reach the limit. But customers can send emails anyway, over the limit. Found some Script Errors. I have translated it from german to english:
Runtime Error Microsoft VBScript - Error: 800A0009 Description: Index out of Range: number....
Runtime Error Microsoft VBScript - Error: 800A01F4 Description: Variable is not declared: 'dom' - Line 535 Column: 3

Whats going wrong?

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-12-05 14:39

Version #2.3 - Minor Fix to declare two undeclared variables which worked fine until you put option explicit in script.
Version #2.2 - Fix to put to put From and FromAddress the right way round and to preserve user name where it exists
Version #2.1

This script is an updated and modified version of Andyp's orginal version ( see topic: viewtopic.php?f=20&t=13824)

This topic has been started to make this new version more easily accessible.

This script limits the outbound emails either by user account or by domain. It also calculates an average over the last x days and when the total amount of outbound emails reaches a defined level the mail is also blocked.

The primary reason for this script is the higher security. If one or some account gets hacked the damage is limited. And it allows the email administrator to limit abuse by valid users sending out mass mailings.

How does user or domain limits work?
You define a general user and domain limit. In a separate file you can also define exceptions for users or domain. The script counts every mail and if the amount reaches the limit a message will be send and the mail will be rejected. You can also define a warning level, when an email is send saying the limits will be reached soon. These mails can be send to the admin or the user.

How does server average limit work?
The script counts the outbound mail of the server and calculates an average over the last x days. When the server passes a threshold factor, let's say 5 times more than the average over the last 20 days the script rejects the mail. An email is send to the admin, also when a warning level is reached.

Note 1:
Since I didn't write the original script and haven't checked all logic in it, I assume it does what it's supposed to. It seems to work for my light testing. I just cleaned up some code and fixed a bug or two others had discovered.

Note 2:
Since this script uses filesystem to open, read, write, close upto 4 files for each email processed, it has the potential to slow down message processing. This may be significant on a busy server but apprently works fine for most people.
You have been warned.

Install instructions are in the zip file.

Good luck with it...
LimitSMTP_#2.3.zip
EDIT: Since this posting, this script has since has a minor modification to handle file locking better. Version #2.3.1 can be found here: viewtopic.php?p=175988#p175988

Rob887
New user
New user
Posts: 19
Joined: 2013-12-10 12:12

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by Rob887 » 2013-12-10 14:06

Having a bit of a problem with this. (sorry if this has been covered)

We are getting warning email and then getting the blocked e-mail

But we are still able to send out emails from that address?

Kind regards

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-12-10 15:42

Don't have answer for you. Impossible to debug what you have done without being able to see code. Most people don't have a problem with it so I can only guess you have not implemented it correctly.

Rob887
New user
New user
Posts: 19
Joined: 2013-12-10 12:12

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by Rob887 » 2013-12-10 16:08

percepts wrote:Don't have answer for you. Impossible to debug what you have done without being able to see code. Most people don't have a problem with it so I can only guess you have not implemented it correctly.
Umm, Its just odd as I've not changed any code or anything apart from the dirs and user name ect.

Is there anything i can post to help?

Cheers

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-12-10 16:13

Your complete eventhandlers.vbs. If I get time I'll have a look at it.

Rob887
New user
New user
Posts: 19
Joined: 2013-12-10 12:12

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by Rob887 » 2013-12-10 16:20

Thanks for that.

The eventlog does update with a X at the end when the limit is hit and also get a email saying locked but the email count still goes up and still able to send emails

Code: Select all

'   Sub OnClientConnect(oClient)
'   End Sub

'   Sub OnAcceptMessage(oClient, oMessage)
'   End Sub

'   Sub OnDeliveryStart(oMessage)
'   End Sub

'   Sub OnDeliverMessage(oMessage)
'   End Sub

'   Sub OnBackupFailed(sReason)
'   End Sub

'   Sub OnBackupCompleted()
'   End Sub

'   Sub OnError(iSeverity, iCode, sSource, sDescription)
'   End Sub

'   Sub OnDeliveryFailed(oMessage, sRecipient, sErrorMessage)
'   End Sub

'   Sub OnExternalAccountDownload(oMessage, sRemoteUID)
'   End Sub



'------------------------------------------------------------------
' Global variables and settings
'------------------------------------------------------------------


'Force error on undeclared variables
Option Explicit

'------------------------------------------------------------------
' SMTP Limit - Global variables and settings
'------------------------------------------------------------------

'General
Public obApp
Public domain_buffer
Public Const ipslocalhost = "127.0.0.1#**.*.*.*"  'separated by #  
Public Const user = "Administrator"
Public Const pw = "Penis"         ' ## enter your hmail admin password here

Public Const write_log_active = False

'User and Domain outgoing limitation
Public Const outgoingstore = "C:\Program Files\hMailServer\Events\outboundstore.txt"
Public Const outgoingexceptions = "C:\Program Files\hMailServer\Events\outboundexceptions.txt"
Public Const outgoingstoreavg = "C:\Program Files\hMailServer\Events\outboundstoreavg.txt"
Public Const max_emails_per_user = 20
Public Const max_emails_per_domain = 200
Public Const warning_factor = 0.8
Public Const server_average_days = 20     ' 0 will deactivate
Public Const server_average_threshold_factor = 10
Public Const warning_factor_avg = 0.6
Public Const msg_AdminName  = """Email Admin"""    ' ## enter name here. N.B. leave """ as is. 
Public Const msg_AdminEmail = "admin@*****.com"   ' ## enter your email admin email address here



Sub OnAcceptMessage(oClient, oMessage)
	Result.Value = 0
	Set obApp = CreateObject("hMailServer.Application")
	Call obApp.Authenticate(user, pw)
	
	If has_client_authenticated(oClient) Then
		write_log ("  User has authenticated. User " & oCLient.username & ", Client " & oClient.IPAddress)
		if not check_outgoing_limitations(oClient, oMessage) Then
			Result.Message = "Your account/Mailserver has passed SMTP outgoing limits."
			Result.Value = 2
		End if
	End if
End Sub

'------------------------------------------------------------------
' SMTP Limit - Functions and Subs for outgoing emails of domain and user 
'------------------------------------------------------------------

function check_outgoing_limitations(oClient, oMessage)
	check_outgoing_limitations = true
	Const ForReading = 1, ForWriting = 2, ForAppending = 8
	Dim fs , f
	Set fs = CreateObject("scripting.filesystemobject")
	Dim idt
	Dim content
	Dim ln
	Dim arr
	Dim usern
	Dim usernadd
	Dim usernnr
	Dim usernnrmax
	Dim domn
	Dim domnadd
	Dim domnnr
	Dim domnnrmax
	Dim reason
	Dim rcptscnt
	Dim dayamounts(200)
	Dim i, k
	
	For i = 0 To 200
		dayamounts(i) = 0
	Next 
	Dim pos
	Dim avg
	Dim minday
	minday = 999999
	Dim toindex
	Dim excptn
	
	write_log("  SMTP outgoing limitations")
	
	If oclient.username <> "" Then
		If instr(1,oclient.username,"@") = 0 Then
			usern = oclient.username & "@" & obApp.Settings.DefaultDomain
			domn = "@" & obApp.Settings.DefaultDomain
		Else
			usern = oclient.username
			domn = Mid(oclient.username,InStr(1,oclient.username,"@"))
		End If
	ElseIf is_local_domain(omessage.fromaddress) then
		usern = omessage.fromaddress
		domn = Mid(omessage.fromaddress,InStr(1,omessage.fromaddress,"@"))
	Else
		usern = "local"
		domn = "@local"
	End If
	content = "# SMTP outgoing storage" & nl & nl
	usernadd = true
	domnadd = true
	usernnr = 1
	domnnr = 1
	usernnrmax = max_emails_per_user
	domnnrmax = max_emails_per_domain
	idt = CLng(Date())
	rcptscnt = omessage.Recipients.count
	write_log("   Number of recipients " & rcptscnt)
	
	write_log("   Reading exceptions file " & outgoingexceptions)
	If fs.FileExists(outgoingexceptions) Then
		Set f = fs.OpenTextFile(outgoingexceptions, ForReading)
		Do While Not f.AtEndOfStream
			ln = f.ReadLine
			If ln <> "" And Mid(ln,1,1) <> "#" And Len(ln) > 3 Then
				arr = Split(ln,Chr(9))
				If UBound(arr) = 1 Then
					If arr(0) = usern Then
						usernnrmax = CLng(arr(1))
						write_log ("    new user limit " & ln)
					End if
					If arr(0) = domn Then
						domnnrmax = CLng(arr(1))
						write_log ("    new domain limit " & ln)
					End if
				Else
					write_log ("    cannot process line " & Mid(ln,1,25))
				End If
			ElseIf Len(ln) > 5 And f.Line > 4 + 1 then
				write_log ("    skipping line " & Mid(ln,1,25))
			End If
		Loop
	Else
		Set f = fs.OpenTextFile(outgoingexceptions, ForWriting, true)
		f.Write("# Outgoing limitation exceptions tab / chr(9) separated" & nl)
		f.Write("# Examples (without # at the beginning)" & nl)
		f.Write("# @yourdomain.com	10000" & nl)
		f.Write("# address@yourdomain.com	5000" & nl & nl)
		f.Close 
	End If
	
	write_log("   Reading storage file " & outgoingstore)
	If fs.FileExists(outgoingstore) Then
		Set f = fs.OpenTextFile(outgoingstore, ForReading)
		Do While Not f.AtEndOfStream
			ln = f.ReadLine
			If ln <> "" And Mid(ln,1,1) <> "#" And Len(ln) > 5 Then
				arr = Split(ln," ")
				If UBound(arr) > 1 Then
					If minday > CLng(arr(0)) Then
						minday = CLng(arr(0))
					End If
				End If
				If UBound(arr) = 2 Or UBound(arr) = 3 Then
					If CLng(arr(0)) = idt And arr(2) = usern Then
						usernnr = CLng(arr(1)) + rcptscnt
						usernadd = False
						write_log ("    adding to line " & ln)
						If usernnr > usernnrmax Then
							If UBound(arr) = 3 Then
								If arr(3) = "X" then
									write_log ("    deny already sent")
								Else
									write_log ("    sending deny")
									outgoing_limitations_send_message oClient, oMessage, false, usernnr, usernnrmax, false
								End if
							Else
								write_log ("    sending deny")
								outgoing_limitations_send_message oClient, oMessage, false, usernnr, usernnrmax, false
							End If
							content = content & arr(0) & " " & usernnr & " " & arr(2) & " X" & nl
						ElseIf usernnr > usernnrmax * warning_factor then
							If UBound(arr) = 3 Then
								If arr(3) = "W" then
									write_log ("    warning already sent")
								Else
									write_log ("    sending warning")
									outgoing_limitations_send_message oClient, oMessage, true, usernnr, usernnrmax, false
								End if
							Else
								write_log ("    sending warning")
								outgoing_limitations_send_message oClient, oMessage, true, usernnr, usernnrmax, false
							End If
							content = content & arr(0) & " " & usernnr & " " & arr(2) & " W" & nl
						Else
							content = content & arr(0) & " " & usernnr & " " & arr(2) & nl
						End if
					elseIf CLng(arr(0)) = idt And arr(2) = domn Then
						domnnr = CLng(arr(1)) + rcptscnt
						domnadd = false
						write_log ("    adding to line " & ln)
						If domnnr > domnnrmax Then
							If UBound(arr) = 3 Then
								If arr(3) = "X" then
									write_log ("    deny already sent")
								Else
									write_log ("    sending deny")
									outgoing_limitations_send_message oClient, oMessage, false, domnnr, domnnrmax, true
								End if
							Else
								write_log ("    sending deny")
								outgoing_limitations_send_message oClient, oMessage, false, domnnr, domnnrmax, true
							End If
							content = content & arr(0) & " " & domnnr & " " & arr(2) & " X" & nl
						ElseIf domnnr > domnnrmax * warning_factor then
							If UBound(arr) = 3 Then
								If arr(3) = "W" then
									write_log ("    warning already sent")
								Else
									write_log ("    sending warning")
									outgoing_limitations_send_message oClient, oMessage, true, domnnr, domnnrmax, true
								End if
							Else
								write_log ("    sending warning")
								outgoing_limitations_send_message oClient, oMessage, true, domnnr, domnnrmax, true
							End If
							content = content & arr(0) & " " & domnnr & " " & arr(2) & " W" & nl
						Else
							content = content & arr(0) & " " & domnnr & " " & arr(2) & nl
						End if
					ElseIf CLng(arr(0)) < idt - server_average_days Then
						write_log ("    deleting line " & ln)
					Else
						content = content & arr(0) & " " & arr(1) & " " & arr(2) & nl
						'write_log ("    copying line " & ln)
					End If
					If Mid(arr(2),1,1) <> "@" Then
						pos = idt - CLng(arr(0))
						dayamounts(pos) = dayamounts(pos) + CLng(arr(1))
					End If
				Else
					write_log ("    cannot process line " & Mid(ln,1,25))
				End If
			ElseIf Len(ln) > 5 And f.Line > 1 + 1 then
				write_log ("    skipping line " & Mid(ln,1,25))
			End If
		Loop
		f.Close
		If usernadd Then
			content = content & idt & " " & usernnr & " " & usern & nl
		End If
		If domnadd Then
			content = content & idt & " " & domnnr & " " & domn & nl
		End If
		Set f = fs.OpenTextFile(outgoingstore, ForWriting, true)
		f.Write(content)
		f.Close 
	Else
		content = content & idt & " " & usernnr & " " & usern & nl
		content = content & idt & " " & domnnr & " " & domn & nl
		Set f = fs.OpenTextFile(outgoingstore, ForWriting, true)
		f.Write(content)
		f.Close 
	End If
	
	toindex = idt - minday
	avg = CDbl(0)
	If toindex >=5 then
		For i = 1 To toindex
			avg = avg + CDbl(dayamounts(i))
		Next
		avg = CDbl(avg) / CDbl(toindex)
		write_log("   Statistic calculation over " & server_average_days & " days")
		write_log("     todays amount " & dayamounts(0) & "   average " & avg & "   maximum " & avg * server_average_threshold_factor)
		write_log("   Checking statistics")
	End If
	If toindex < 5 then
		write_log("   Statistic calculation is only done over at least 5 days. Available days: " & toindex)
	ElseIf avg < 5 Then
		write_log("     average below 5 mails per day, ignoring average statistic")
	ElseIf dayamounts(0) > avg * server_average_threshold_factor Then
		write_log("     todays amount has passed limit of " & avg * server_average_threshold_factor)
		outgoing_limitations_avg_send_admin dayamounts(0),avg * server_average_threshold_factor,false
		check_outgoing_limitations = False
	ElseIf dayamounts(0) > avg * server_average_threshold_factor * warning_factor_avg Then
		write_log("     todays amount has passed warning level of " & avg * server_average_threshold_factor * warning_factor_avg)
		outgoing_limitations_avg_send_admin dayamounts(0),avg * server_average_threshold_factor,true
		check_outgoing_limitations = False
	Else
		write_log("     within limits")
	End If
	
	write_log("   Checking limits")
	If usernnrmax < usernnr Then
		check_outgoing_limitations = false
		write_log("     max of user passed!")
	ElseIf domnnrmax < domnnr Then
		check_outgoing_limitations = false
		write_log("     max of domain passed!")
	Else
		write_log("     within limits")
	End If
	
	excptn = false
	If oMessage.FromAddress = msg_AdminEmail Then
		excptn = true
	Else
		For k = 0 To oMessage.recipients.count - 1
			If oMessage.recipients(k).OriginalAddress = msg_AdminEmail Then
				excptn = True
			End If
		Next
	End If
	If excptn = True Then
		write_log("   Mail from/to admin -> passes lock")
		check_outgoing_limitations = true
	End if
End function

Sub outgoing_limitations_avg_send_admin(nr, max, iswarning)
	Const ForReading = 1, ForWriting = 2, ForAppending = 8
	Dim fs , f
	Set fs = CreateObject("scripting.filesystemobject")
	Dim txt
	Dim tmp
	Dim str
	Dim out
	Dim snd
	
	If iswarning Then
		tmp = "Warning: Todays outgoing emails will reach lock soon"
		
		txt = "Hello " & msg_AdminEmail & nl & nl
		txt = txt & "todays outgoing email will reach avg limit soon." & nl & nl
		txt = txt & "Current amount is " & nr & nl
		txt = txt & "Limit is " & max & nl & nl
		txt = txt & "Regards" & nl
		txt = txt & msg_AdminEmail
		
		str = "W" & CLng(Date())
	Else
		tmp = "Locked: Todays outgoing emails have passed avg limit"
		
		txt = "Hello " & msg_AdminEmail & nl & nl
		txt = txt & "todays outgoing email have passed avg limit." & nl & nl
		txt = txt & "Current amount is " & nr & nl
		txt = txt & "Limit is " & max & nl & nl
		txt = txt & "Regards" & nl
		txt = txt & msg_AdminEmail
		
		str = "X" & CLng(Date())
	End If
	
	snd = true
	If fs.FileExists(outgoingstoreavg) Then
		Set f = fs.OpenTextFile(outgoingstoreavg,ForReading)
		out = f.ReadAll
		f.Close
		If out = str Then
			snd = false
		End If
	End If
	
	If snd then
		Set nMessage = CreateObject("hMailServer.Message")
		nMessage.From = msg_AdminName & " <" & msg_AdminEmail & ">"
		nMessage.FromAddress = msg_AdminEmail
		nMessage.AddRecipient msg_AdminName, msg_AdminEmail
		nMessage.Subject = tmp
		nMessage.Body = txt
		nMessage.Save
		
		Set f = fs.OpenTextFile(outgoingstoreavg,ForWriting,True)
		f.Write(str)
		f.Close
	End If
End Sub

Sub outgoing_limitations_send_message(oClient, oMessage, iswarning, nr, max, isdomain)
	Dim txt
	Dim tmp
	Dim nMessage
	Dim strAccount
	Dim strFromName
	Dim strFromAddress
		
	tmp = oMessage.From
 
 if (InStr(1, oMessage.From, "<", 1) > 0) Then
	 strAccount       = split(oMessage.From, "<")
  strFromAddress   = Replace(strAccount(1), ">", "")
  strFromName      = Trim(strAccount(0))
  strFromName      = Replace (strFromName, """", "")
 Else 
  strFromAddress   = oMessage.From
	 strAccount       = split(oMessage.From, "@")
  strFromName      = strAccount(0)
 End If 
	
	If iswarning Then
		txt = "Hello " & tmp & nl & nl
		txt = txt & "you will soon reach your account limits." & nl & nl
		txt = txt & "Current amount is " & nr & nl
		txt = txt & "Limit is " & max & nl & nl
		If isdomain Then
			txt = txt & "This is a limit of the your domain." & nl & nl
		Else
			txt = txt & "This is a limit of the your account." & nl & nl
		End If
		txt = txt & "Regards" & nl
		txt = txt & msg_AdminEmail
		
  Set nMessage = CreateObject("hMailServer.Message")
		nMessage.From = msg_AdminName & " <" & msg_AdminEmail & ">"
		nMessage.FromAddress = msg_AdminEmail
  nMessage.AddRecipient msg_AdminName, msg_AdminEmail
  nMessage.Subject = "Warning: Account limits will be reached soon"
  nMessage.Body = txt
  nMessage.Save
		
		Set nMessage = CreateObject("hMailServer.Message")
		nMessage.From = msg_AdminName & " <" & msg_AdminEmail & ">"
		nMessage.FromAddress = msg_AdminEmail
		nMessage.AddRecipient strFromName, strFromAddress
		nMessage.Subject = "Warning: Account limits will be reached soon"
		nMessage.Body = txt
		nMessage.Save
	Else
		txt = "Hello " & tmp & nl & nl
		txt = txt & "you have passed your account limits." & nl & nl
		txt = txt & "Current amount is " & nr & nl
		txt = txt & "Limit is " & max & nl & nl
		If isdomain Then
			txt = txt & "This is a limit of the your domain." & nl & nl
		Else
			txt = txt & "This is a limit of the your account." & nl & nl
		End If
		txt = txt & "Regards" & nl
		txt = txt & msg_AdminEmail
		
		Set nMessage = CreateObject("hMailServer.Message")
		nMessage.From = msg_AdminName & " <" & msg_AdminEmail & ">"
		nMessage.FromAddress = msg_AdminEmail
		nMessage.AddRecipient msg_AdminName, msg_AdminEmail
		nMessage.Subject = "Locked: Account limits passed"
		nMessage.Body = txt
		nMessage.Save

		Set nMessage = CreateObject("hMailServer.Message")
		nMessage.From = msg_AdminName & " <" & msg_AdminEmail & ">"
		nMessage.FromAddress = msg_AdminEmail
		nMessage.AddRecipient strFromName, strFromAddress
		nMessage.Subject = "Locked: Account limits passed"
		nMessage.Body = txt
		nMessage.Save
	End If
End Sub

'------------------------------------------------------------------
' General functions of all scripts
'------------------------------------------------------------------

Sub write_log(txt)
	If write_log_active then
		EventLog.Write("Limit SMTP Script:"+txt)
	End if
End Sub

Function get_date
	Dim tmp
	Dim erg
	tmp = Year(Date)
	erg = CStr(tmp)
	
	If Month(Date) < 10 Then
		tmp = "0" & Month(Date)
	Else
		tmp = Month(Date)
	End If
	erg = erg & "-" & tmp
	
	If day(Date) < 10 Then
		tmp = "0" & day(Date)
	Else
		tmp = day(Date)
	End If
	erg = erg & "-" & tmp
	
	get_date = erg
End Function

Function nl
	nl = Chr(13) & Chr(10)
End function

Function is_local_domain(domain_or_email)
	is_local_domain = False
	Dim domain
	Dim dom
	Dim doms
	Dim als
	Dim alss
	Dim i
	Dim j
	
	If InStr(1,"  " & domain_or_email,"@") > 0 Then
		domain = Mid(domain_or_email, InStr(1,domain_or_email,"@") + 1)
	Else
		domain = domain_or_email
	End If
	
	If domain_buffer = "" then
		i = 0
		Set doms = obapp.Domains
		Do While i <= doms.Count - 1
			Set dom = doms.Item(i)
			domain_buffer = domain_buffer & "#" & dom.Name
			j = 0
			Set alss = dom.DomainAliases
			Do While j <= alss.Count - 1
				Set als = alss.item(j)
				domain_buffer = domain_buffer & "#" & als.AliasName
				j = j + 1
			Loop
			i = i + 1
		Loop
	End If
	
	If InStr(1, "  " & domain_buffer, domain) > 0 Then
		is_local_domain = True
	End If
End Function

Function has_client_authenticated(oclient)
	has_client_authenticated = false
	If oCLient.username <> "" Or InStr(1,"  " & ipslocalhost, oClient.IPAddress) > 0 Then
		has_client_authenticated = true
	End if
End Function

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-12-10 16:40

quick scan and it looks to be implemented OK

on thing which looks odd is

Public Const ipslocalhost = "127.0.0.1#**.*.*.*"

try

Public Const ipslocalhost = "0.0.0.0"

but I have no idea what the problem is.

Have the three txt files been created in hmailserver/events and what do they contain?

I don't think the script stops or counts local sends, only external

Note: I did not write this script. I just made some mods to fix bugs others had reported.

Rob887
New user
New user
Posts: 19
Joined: 2013-12-10 12:12

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by Rob887 » 2013-12-10 16:55

percepts wrote:quick scan and it looks to be implemented OK

on thing which looks odd is

Public Const ipslocalhost = "127.0.0.1#**.*.*.*"

try

Public Const ipslocalhost = "0.0.0.0"

but I have no idea what the problem is.

Have the three txt files been created in hmailserver/events and what do they contain?

I don't think the script stops or counts local sends, only external

Note: I did not write this script. I just made some mods to fix bugs others had reported.
Thanks for your help.

I've changed the local host IP.

I'm connecting from a remote computer and sending to a external email (a Hotmail that i have access to)
Would IP Range effect this script do you know ?

Code: Select all

# SMTP outgoing storage

41618 13 sales@*****.com X
41618 13 @***.com
41618 2 local
41618 2 @local
The other TXT everything is ignored behind #'s

I'm also running "hMailServer 5.4 - Build 1950" What builds has this been testing on?

Thank you

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-12-10 17:01

It runs on my 5.4 Build 1950.

IP-range shouldn't make any difference. The mail has already been accepted by hmail.

Rob887
New user
New user
Posts: 19
Joined: 2013-12-10 12:12

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by Rob887 » 2013-12-10 17:31

Seem a bit odd as its doing everything but blocking the emails, I've not had time to go though the code as i'm at work.

Code: Select all

[b]Warning: Account limits will be reached soon
[/b]

Hello " (Rob)" <sales@tre.com>

you will soon reach your account limits.

Current amount is 19
Limit is 20

This is a limit of the your account.

Regards
sales@tre.com


Locked: Account limits passed


Hello "Rob" <sales@tre.com>

[b]you have passed your account limits.[/b]

Current amount is 21
Limit is 20

This is a limit of the your account.

Regards
sales@tre.com
I get two of them emails into my inbox.

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-12-10 17:41

The first of those messages is a warning and not a block.
The second is a block.

When you send mail does your email client tell you about the block with a 554 message?

Well I just tested again and it works for me. After I reach the account or domain limit no more mails are sent to recipient.

However, every time user tries to send another email the count WILL be increased but the mail is not sent and admin email will receive a notification email which is really annoying but doesn't mean the message was actually sent. The users email client should be seeing a 554 Your account limit has passed smtp outgoing limits.

And note that user will receive warning messages about approaching limit and continue to be able to send until actual limit is hit.

Have you actually verified that hotmail is receiving more than account limit? My test sending to gmail shows that once limit is reached subsequent sends don't happen and my email client says so.

Rob887
New user
New user
Posts: 19
Joined: 2013-12-10 12:12

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by Rob887 » 2013-12-10 18:04

percepts wrote:The first of those messages is a warning and not a block.
The second is a block.

When you send mail does your email client tell you about the block with a 554 message?

Well I just tested again and it works for me. After I reach the account or domain limit no more mails are sent to recipient.

However, every time user tries to send another email the count WILL be increased but the mail is not sent and admin email will receive a notification email which is really annoying but doesn't mean the message was actually sent. The users email client should be seeing a 554 Your account limit has passed smtp outgoing limits.

And note that user will receive warning messages about approaching limit and continue to be able to send until actual limit is hit.

Have you actually verified that hotmail is receiving more than account limit? My test sending to gmail shows that once limit is reached subsequent sends don't happen and my email client says so.
Its detecting that we have hit the limit its updating the text with

Code: Select all

41618 21 sales@tre.com X
Its not sending back a 554 or preventing the messages sending.

Its on "41618 21 sales@tre.com X" ATM and i'm still sending emails to Gmail and Hotmail with-out problems.

But we are not getting a email every time we send a email now, I'm guessing its something with the detection of the X array

I'm pretty confused atm, Looks like got a bit of coding to do when i'm home.

Rob887
New user
New user
Posts: 19
Joined: 2013-12-10 12:12

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by Rob887 » 2013-12-10 18:25

Well that was odd ?

I've changed

Code: Select all

Public Const write_log_active = False
to

Code: Select all

Public Const write_log_active = True
It now works.

Bit odd as that only changes something in Sub Write_log

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2013-12-10 19:16

probably something to do with OS file buffering but I'd be guessing.

But then again it works for me with it set to false.

Bill48105
Developer
Developer
Posts: 6192
Joined: 2010-04-24 23:16
Location: Michigan, USA

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by Bill48105 » 2014-01-03 06:08

percepts wrote:Note 2:
Since this script uses filesystem to open, read, write, close upto 4 files for each email processed, it has the potential to slow down message processing. This may be significant on a busy server but apprently works fine for most people.
You have been warned.
Had been too busy to notice this until now. Very cool percepts, with a catch. The above is the main reason I refuse to use this (well andy's) script & instead use an alternate I made that works differently but similar purpose. It makes me cringe to think how unsafe that is to use files like that. Luckily it's just stats so it's not critical but that's the furthest from safe for multi-threading there is. Aside from the massive overhead it's just begging for race condition, lost data or data corruption. (again luckily just stats but still) Honestly I'm surprised people don't have big problems running these file-based "database" scripts except for maybe just lucky or server load is low enough. I had commented on Andy's suggesting someone modify the script to use a database instead of files. It'd have much lower overhead & should be safer in a multi-threaded server environment.

It's good you're keeping andy's script alive as it's needed but hopefully at some point someone will take the time to move away from the files. :)
Bill
hMailServer build LIVE on my servers: 5.4-B2014050402
#hmailserver on FreeNode IRC https://webchat.freenode.net/?channels=#hmailserver
*** ABSENT FROM hMail! Those in IRC know how to find me if urgent. ***

Agostino
New user
New user
Posts: 17
Joined: 2014-01-19 19:29

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by Agostino » 2014-01-19 19:53

Hi, thanks for the script! I need it!

I don't understand how it works:

- into the script i should write the limits for all users and for all domains
- into the outboundstore.txt i see the number of mail sent from user and domain

but:

- when does the script block outgoing mail? when the users reach the average of (at least) last 5 days or when reach the limit set into the script?
- where is the average?
- what is the first number repeated in all the lines of outboundstore.txt?

Thank yout!

percepts
Senior user
Senior user
Posts: 5282
Joined: 2009-10-20 16:33
Location: Sceptred Isle

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by percepts » 2014-01-19 20:33

I have no idea. What does the source code tell you? That is where you will find all the the answers to your questions about the script if you look.

Gubert
New user
New user
Posts: 14
Joined: 2014-01-23 13:02

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by Gubert » 2014-01-23 14:51

Hello,
thanks for the script!

For what period are the variables "max_emails_per_user" and "max_emails_per_domain" defined?
Will this variables reset at any time?

Gubert
New user
New user
Posts: 14
Joined: 2014-01-23 13:02

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by Gubert » 2014-02-05 15:27

Found it. In the original script it is daily. I will test it. Maybe i will change it to a higher rate. Because 100 mails per day and user is not much.
Where? I've read the manual 100 times and found nothing...

agserna
Normal user
Normal user
Posts: 69
Joined: 2011-10-05 23:43

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by agserna » 2014-07-03 15:26

Bill48105 wrote:It's good you're keeping andy's script alive as it's needed but hopefully at some point someone will take the time to move away from the files. :)
Bill


Fully agree with you bill.

Using this script on a production server is dangerous, especially if it is connected to the internet through something more than an ADSL/line

Why?

day's ago one account in our mailserver was used to send spam (stolen credentials) and that script failed to lock that account and crashed mailserver!!!

The script (V2.2) is installed on the server and congigured with 200 emails limit per user and 1000 emails limit per domain, but hundreds of thousand emails was sent (not a mistake when i say hundreds of thousand) from that single account and i have received no emails warnings cause the spammer was sending very little emails (less than 1 Kb) and this generated a very large queue (almost 500.000 files in data root + 200.000 already sent...)

Someone could say "How is this possible?" or "Are you shure 700.000?" Yes i do!!
Bill48105 wrote:It makes me cringe to think how unsafe that is to use files like that....... that's the furthest from safe for multi-threading there is. Aside from the massive overhead it's just begging for race condition, lost data or data corruption.
Bill48105

Again fully agree....

People must realize that there are big differences in using such script on a server connected to a xDSL line and using the same script on a server connectet to the internet with 1Gbit internet connection, what happens in a "minute" for the first is not what happens in a "minute" for the second.

Let me try to explain...

A mailserver conncted to the internet with an ADSL line (usually half or one/two Mb/s upload) will receive/send data very fast but not enough to saturate the processes of iles opening/writing/closing used by this script.

A mailserver conncted to the internet with an 1000 Mb syncronous line will receive and send data so fastly and will suddenly lead to the crash of the processes of files opening/writing/closing used by this script and let the SPAMMER send out without limits and, as for my case, crashing the mailserver....

Months ago i posted in these article that i was experiencing some errors in script counting of sent email and now i undestand why...... If the connection is fast enough the files opening/writing/closing fails....

Dont get me wrong, i have big respect for the hard work done and time spent by those developing, publishing, testing and suggesting the use of third parts add ons for HMS cause this is in the spirit of good collaboration. But, shureley everyones agree with me when i say that also "warn of the potential risks" involved in using some of theese add ons belong to the same spirit.

Bill48105
Developer
Developer
Posts: 6192
Joined: 2010-04-24 23:16
Location: Michigan, USA

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by Bill48105 » 2014-07-03 18:36

agserna wrote:
Bill48105 wrote:It's good you're keeping andy's script alive as it's needed but hopefully at some point someone will take the time to move away from the files. :)
Bill


Fully agree with you bill.

Using this script on a production server is dangerous, especially if it is connected to the internet through something more than an ADSL/line

Why?

day's ago one account in our mailserver was used to send spam (stolen credentials) and that script failed to lock that account and crashed mailserver!!!

The script (V2.2) is installed on the server and congigured with 200 emails limit per user and 1000 emails limit per domain, but hundreds of thousand emails was sent (not a mistake when i say hundreds of thousand) from that single account and i have received no emails warnings cause the spammer was sending very little emails (less than 1 Kb) and this generated a very large queue (almost 500.000 files in data root + 200.000 already sent...)

Someone could say "How is this possible?" or "Are you shure 700.000?" Yes i do!!
Bill48105 wrote:It makes me cringe to think how unsafe that is to use files like that....... that's the furthest from safe for multi-threading there is. Aside from the massive overhead it's just begging for race condition, lost data or data corruption.
Bill48105

Again fully agree....

People must realize that there are big differences in using such script on a server connected to a xDSL line and using the same script on a server connectet to the internet with 1Gbit internet connection, what happens in a "minute" for the first is not what happens in a "minute" for the second.

Let me try to explain...

A mailserver conncted to the internet with an ADSL line (usually half or one/two Mb/s upload) will receive/send data very fast but not enough to saturate the processes of iles opening/writing/closing used by this script.

A mailserver conncted to the internet with an 1000 Mb syncronous line will receive and send data so fastly and will suddenly lead to the crash of the processes of files opening/writing/closing used by this script and let the SPAMMER send out without limits and, as for my case, crashing the mailserver....

Months ago i posted in these article that i was experiencing some errors in script counting of sent email and now i undestand why...... If the connection is fast enough the files opening/writing/closing fails....

Dont get me wrong, i have big respect for the hard work done and time spent by those developing, publishing, testing and suggesting the use of third parts add ons for HMS cause this is in the spirit of good collaboration. But, shureley everyones agree with me when i say that also "warn of the potential risks" involved in using some of theese add ons belong to the same spirit.
I had forgot all about this but once I saw your reply i realize it finally bit someone. I think there is now a database-based script that is similar (MUCH MUCH simpler) but I'd need to find it. And I can't say I've tested it but worth checking into. What i do is enable Archiving which stores copies of mail from each user in a structured tree similar to data tree. Then I have a script I posted that runs on a given interval & scans looking for Sent messages & emails me an alert if any user has more than expected. Could be modified to look for other patterns. The benefit is that it does not run per email (which could be drawback but as long a I catch it quickly it doesn't need to be instantly) and it does not store anything so no worry about race condition for both those reasons.

But yes people have been lucky to not experience issues with file-based storage or perhaps they didn't notice.
Bill
hMailServer build LIVE on my servers: 5.4-B2014050402
#hmailserver on FreeNode IRC https://webchat.freenode.net/?channels=#hmailserver
*** ABSENT FROM hMail! Those in IRC know how to find me if urgent. ***

agserna
Normal user
Normal user
Posts: 69
Joined: 2011-10-05 23:43

Re: Limit Outbound Mails by User, Domain or Server Average #

Post by agserna » 2014-07-04 00:21

Hi Bill
Bill48105 wrote:I think there is now a database-based script that is similar (MUCH MUCH simpler)
I think you are referring to this one http://www.hmailserver.com/forum/viewto ... 20&t=25741
I had a look today but it uses the OnAcceptMessage() to open and close connections via ODBC to an external database and i don't "love" this technique.
Maybe adding the table directly to te HMS database itself and using database object instead of creating/destroing connections for each message would be better but i think that the best thing is completely avoid any activity involving those "low level" mailserver events for performance and stability reasons

Really hope that in the future HMS will natively integrates "high level" protection such limit number of email sent even though this result in a "bit lower performance", see this http://www.hmailserver.com/forum/viewto ... =2&t=25333

In the meantime i think that youre solution is the best compromise so i am thinking to develope a web interface (can be accessed anywhere/anytime) that, at regular time intervals, queryes the mailserver database via stored procedures and checking some parameters (number of emails in queue, number of sent messages and so on) in this way the mailserver events are not involved, no impact on performances and no latency. Using COM API only to disable accounts or change passwords "On the fly" in case of warnings and email me or maybe phone call me via skype or something else....

but at the moment i need to get some info's on how can i distinct between emails sent to local accounts and emails sent from local accounts,
how can I obtain this information from hm_messages And/Or hm_messagesrecipient database tables?

Thanks Again

Post Reply