Moving back the stats module to the core. (#2011)

* Moving back the stats module to the core.

* Added system packages to build RRDtool.

* Fixed unit tests.

* Improved coverage.
This commit is contained in:
Antoine Nguyen
2020-09-17 16:02:39 +02:00
committed by GitHub
parent 0da574a7f4
commit 3df446f657
73 changed files with 6424 additions and 6 deletions
+3 -1
View File
@@ -22,6 +22,8 @@ addons:
- ldap-utils
- postfix
- slapd
- librrd-dev
- rrdtool
cache: pip
@@ -50,7 +52,7 @@ before_script:
script:
- python ./tests.py
- cd test_project
- coverage run manage.py test modoboa.core modoboa.lib modoboa.admin modoboa.limits modoboa.transport modoboa.relaydomains modoboa.dnstools modoboa.ldapsync modoboa.policyd
- coverage run manage.py test modoboa.core modoboa.lib modoboa.admin modoboa.limits modoboa.transport modoboa.relaydomains modoboa.dnstools modoboa.ldapsync modoboa.policyd modoboa.maillog
after_success:
- coverage combine
+1
View File
@@ -16,6 +16,7 @@ class DomainFactory(PermissionFactory):
model = models.Domain
django_get_or_create = ("name", )
name = factory.Sequence(lambda n: "domain{}.test".format(n))
type = "domain" # NOQA:A003
quota = 0
default_mailbox_quota = 10
+4 -1
View File
@@ -172,9 +172,12 @@ Domains.prototype = {
if (this.navobj.getbaseurl() === "list") {
args.objtype = "domain";
this.options.eor_message = gettext("No more domain to show");
} else {
} else if (this.navobj.getbaseurl() === "quota") {
args.objtype = "quota";
this.options.eor_message = gettext("No more quota to show");
} else {
args.objtype = "log";
this.options.eor_message = gettext("No more log to show");
}
return args;
},
@@ -0,0 +1,6 @@
{% load i18n %}
<th class="sortable" data-sort_order="queue_id">{% trans "Queue ID" %}</th>
<th class="sortable" data-sort_order="date">{% trans "Date" %}</th>
<th class="sortable" data-sort_order="sender">{% trans "From" %}</th>
<th class="sortable" data-sort_order="rcpt">{% trans "To" %}</th>
<th class="sortable" data-sort_order="status">{% trans "Status" %}</th>
@@ -0,0 +1,9 @@
{% for log in logs %}
<tr>
<td>{{ log.queue_id }}</td>
<td>{{ log.date|date:"SHORT_DATETIME_FORMAT" }}</td>
<td><span title="{{ log.sender }}">{{ log.sender|truncatechars:30 }}</span></td>
<td>{{ log.rcpt }}</td>
<td>{{ log.status }}</td>
</tr>
{% endfor %}
+7
View File
@@ -36,10 +36,12 @@ def domains_menu(selection, user, ajax_mode=True):
if ajax_mode:
domain_list_url = "list/"
quota_list_url = "quotas/"
logs_url = "logs/"
nav_classes += " ajaxnav"
else:
domain_list_url = reverse("admin:domain_list")
quota_list_url = domain_list_url + "#quotas/"
logs_url = domain_list_url + "#logs/"
entries = [
{"name": "domains",
"label": _("List domains"),
@@ -51,6 +53,11 @@ def domains_menu(selection, user, ajax_mode=True):
"img": "fa fa-hdd-o",
"class": "ajaxnav navigation",
"url": quota_list_url},
{"name": "logs",
"label": _("Message logs"),
"img": "fa fa-list",
"class": "ajaxnav navigation",
"url": logs_url},
]
if user.has_perm("admin.add_domain"):
extra_entries = signals.extra_domain_menu_entries.send(
+26
View File
@@ -16,6 +16,8 @@ from modoboa.core import factories as core_factories
from modoboa.core.models import User
from modoboa.core.tests.test_views import SETTINGS_SAMPLE
from modoboa.lib.tests import ModoTestCase
from modoboa.maillog import factories as ml_factories
from . import utils
from .. import factories
from ..models import Alias, Domain
@@ -336,6 +338,30 @@ class DomainTestCase(ModoTestCase):
response = self.ajax_get("{}?sort_order=allocated_quota".format(url))
self.assertNotEqual(old_rows, response["rows"])
def test_domain_logs_list_view(self):
"""Test logs list view."""
domain = Domain.objects.get(name="test.com")
ml_factories.MaillogFactory(from_domain=domain)
ml_factories.MaillogFactory(to_domain=domain, status="received")
ml_factories.MaillogFactory()
ml_factories.MaillogFactory()
url = reverse("admin:domain_logs_list")
response = self.ajax_get(url)
self.assertIn("ID1", response["rows"])
old_rows = response["rows"]
response = self.ajax_get("{}?sort_order=-sender".format(url))
self.assertNotEqual(old_rows, response["rows"])
response = self.ajax_get("{}?searchquery=ID1".format(url))
self.assertNotEqual(old_rows, response["rows"])
admin = User.objects.get(username="admin@test.com")
self.client.force_login(admin)
url = reverse("admin:domain_logs_list")
response = self.ajax_get(url)
self.assertNotEqual(old_rows, response["rows"])
def test_statitics_widget(self):
"""Test statistics display in dashboard."""
url = reverse("core:dashboard")
+2
View File
@@ -24,6 +24,8 @@ urlpatterns = [
path('domains/list/', domain_views._domains, name="_domain_list"),
path('domains/quotas/', domain_views.list_quotas,
name="domain_quota_list"),
path('domains/logs/', domain_views.list_logs,
name="domain_logs_list"),
path('domains/flatlist/', domain_views.domains_list,
name="domain_flat_list"),
path('domains/new/', domain_views.newdomain, name="domain_add"),
+45 -3
View File
@@ -8,7 +8,7 @@ from django.contrib.auth import mixins as auth_mixins
from django.contrib.auth.decorators import (
login_required, permission_required, user_passes_test
)
from django.db.models import Sum
from django.db.models import Q, Sum
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.template.loader import render_to_string
@@ -21,6 +21,8 @@ from modoboa.core import signals as core_signals
from modoboa.lib.exceptions import PermDeniedException
from modoboa.lib.listing import get_listing_page, get_sort_order
from modoboa.lib.web_utils import render_to_json_response
from modoboa.maillog import models as ml_models
from .. import signals
from ..forms import DomainForm, DomainWizard
from ..lib import get_domains
@@ -119,9 +121,12 @@ def domains(request, tplname="admin/domains.html"):
)
def get_next_page(request):
"""Return the next page of the domain or quota list."""
if request.GET.get("objtype", "domain") == "domain":
objtype = request.GET.get("objtype", "domain")
if objtype == "domain":
return _domains(request)
return list_quotas(request)
if objtype == "quota":
return list_quotas(request)
return list_logs(request)
@login_required
@@ -160,6 +165,43 @@ def list_quotas(request):
return render_to_json_response(context)
@login_required
@permission_required("admin.view_domain")
def list_logs(request):
"""List all Maillog entries."""
sort_order, sort_dir = get_sort_order(request.GET, "date")
search = request.GET.get("searchquery")
if not request.user.is_superuser:
domains = Domain.objects.get_for_admin(request.user)
logs = ml_models.Maillog.objects.filter(
Q(from_domain__in=domains) | Q(to_domain__in=domains)
)
else:
logs = ml_models.Maillog.objects.all()
logs = logs.order_by("{}{}".format(sort_dir, sort_order))
if search:
logs = logs.filter(
Q(sender__icontains=search) |
Q(rcpt__icontains=search) |
Q(queue_id__icontains=search) |
Q(status__icontains=search)
)
page = get_listing_page(logs, request.GET.get("page", 1))
context = {
"headers": render_to_string(
"admin/domains_log_headers.html", {}, request
)
}
if page is None:
context["length"] = 0
else:
context["rows"] = render_to_string(
"admin/domains_logs.html", {"logs": page}, request
)
context["pages"] = [page.number]
return render_to_json_response(context)
@login_required
@permission_required("admin.add_domain")
@reversion.create_revision()
@@ -81,6 +81,7 @@ MODOBOA_APPS = (
'modoboa.limits',
'modoboa.parameters',
'modoboa.dnstools',
'modoboa.maillog',
# Modoboa extensions here.
{% for extension in extensions %} '{{ extension }}',
{% endfor %}
+4 -1
View File
@@ -89,7 +89,10 @@ SETTINGS_SAMPLE = {
"core-sms_provider": "",
"core-sms_ovh_endpoint": "ovh-eu",
"core-password_recovery_msg": "",
"core-ldap_dovecot_sync": False
"core-ldap_dovecot_sync": False,
"maillog-logfile": "/var/log/mail.log",
"maillog-rrd_rootdir": "/tmp",
"maillog-greylist": False,
}
+1
View File
@@ -0,0 +1 @@
default_app_config = "modoboa.maillog.apps.MaillogConfig"
+16
View File
@@ -0,0 +1,16 @@
"""AppConfig for stats."""
from django.apps import AppConfig
from .forms import load_settings
class MaillogConfig(AppConfig):
"""App configuration."""
name = "modoboa.maillog"
verbose_name = "Modoboa graphical statistics"
def ready(self):
load_settings()
from . import handlers
+25
View File
@@ -0,0 +1,25 @@
"""App. factories."""
import factory
from django.utils import timezone
from modoboa.admin import factories as admin_factories
from . import models
class MaillogFactory(factory.DjangoModelFactory):
"""Factory class for Maillog."""
class Meta:
model = models.Maillog
queue_id = factory.Sequence(lambda n: "ID{}".format(n))
date = timezone.now()
sender = factory.Sequence(lambda n: "sender{}@example.test".format(n))
rcpt = factory.Sequence(lambda n: "rcpt{}@example2.test".format(n))
size = 100
status = "sent"
from_domain = factory.SubFactory(admin_factories.DomainFactory)
to_domain = factory.SubFactory(admin_factories.DomainFactory)
+59
View File
@@ -0,0 +1,59 @@
"""Modoboa stats forms."""
import rrdtool
from pkg_resources import parse_version
from django.conf import settings
from django.utils.translation import ugettext_lazy
from django import forms
from modoboa.lib import form_utils
from modoboa.parameters import forms as param_forms
class ParametersForm(param_forms.AdminParametersForm):
"""Stats global parameters."""
app = "maillog"
general_sep = form_utils.SeparatorField(label=ugettext_lazy("General"))
logfile = forms.CharField(
label=ugettext_lazy("Path to the log file"),
initial="/var/log/mail.log",
help_text=ugettext_lazy("Path to log file used to collect statistics"),
widget=forms.TextInput(attrs={"class": "form-control"})
)
rrd_rootdir = forms.CharField(
label=ugettext_lazy("Directory to store RRD files"),
initial="/tmp/modoboa",
help_text=ugettext_lazy(
"Path to directory where RRD files are stored"),
widget=forms.TextInput(attrs={"class": "form-control"})
)
greylist = form_utils.YesNoField(
label=ugettext_lazy("Show greylisted messages"),
initial=False,
help_text=ugettext_lazy(
"Differentiate between hard and soft rejects (greylisting)")
)
def __init__(self, *args, **kwargs):
"""Check RRDtool version."""
super().__init__(*args, **kwargs)
rrd_version = parse_version(rrdtool.lib_version())
required_version = parse_version("1.6.0")
test_mode = getattr(settings, "RRDTOOL_TEST_MODE", False)
if rrd_version < required_version and not test_mode:
del self.fields["greylist"]
def load_settings():
"""Load app settings."""
from modoboa.parameters import tools as param_tools
param_tools.registry.add(
"global", ParametersForm, ugettext_lazy("Statistics"))
+269
View File
@@ -0,0 +1,269 @@
"""Classes to define graphics."""
import inspect
from itertools import chain
import os
from lxml import etree
import six
from django.conf import settings
from django.utils.encoding import smart_bytes, smart_text
from django.utils.translation import ugettext as _, ugettext_lazy
from modoboa.admin import models as admin_models
from modoboa.lib import exceptions
from modoboa.lib.sysutils import exec_cmd
from modoboa.parameters import tools as param_tools
class Curve:
"""Graphic curve.
Simple way to represent a graphic curve.
"""
def __init__(self, dsname, color, legend, cfunc="AVERAGE"):
"""Constructor.
"""
self.dsname = dsname
self.color = color
self.legend = legend
self.cfunc = cfunc
def to_rrd_command_args(self, rrdfile):
"""Convert this curve to the approriate RRDtool command.
:param str rrdfile: RRD file name
:return: a list
"""
rrdfile = os.path.join(
param_tools.get_global_parameter("rrd_rootdir"), "%s.rrd" % rrdfile
)
return [
'DEF:%s=%s:%s:%s' %
(self.dsname, rrdfile, self.dsname, self.cfunc),
'CDEF:%(ds)spm=%(ds)s,UN,0,%(ds)s,IF,60,*' % {"ds": self.dsname},
'XPORT:%spm:"%s"' % (self.dsname, self.legend)
]
class Graphic:
"""Graphic."""
def __init__(self):
"""Constructor."""
self._curves = []
try:
order = getattr(self, "order")
except AttributeError:
for member in inspect.getmembers(self):
if isinstance(member[1], Curve):
self._curves += [member[1]]
else:
for name in order:
try:
curve = getattr(self, name)
except AttributeError:
continue
if not isinstance(curve, Curve):
continue
self._curves += [curve]
@property
def display_name(self):
return self.__class__.__name__.lower()
@property
def rrdtool_binary(self):
"""Return path to rrdtool binary."""
dpath = None
code, output = exec_cmd("which rrdtool")
if not code:
dpath = output.strip()
else:
known_paths = getattr(
settings, "RRDTOOL_LOOKUP_PATH",
("/usr/bin/rrdtool", "/usr/local/bin/rrdtool")
)
for fpath in known_paths:
if os.path.isfile(fpath) and os.access(fpath, os.X_OK):
dpath = fpath
if dpath is None:
raise exceptions.InternalError(
_("Failed to locate rrdtool binary."))
return smart_text(dpath)
def export(self, rrdfile, start, end):
"""Export data to XML using rrdtool and convert it to JSON."""
result = []
cmdargs = []
for curve in self._curves:
result += [{
"name": str(curve.legend),
"color": curve.color, "data": []
}]
cmdargs += curve.to_rrd_command_args(rrdfile)
code = 0
cmd = "{} xport --start {} --end {} ".format(
self.rrdtool_binary, str(start), str(end))
cmd += " ".join(cmdargs)
code, output = exec_cmd(smart_bytes(cmd))
if code:
return []
tree = etree.fromstring(output)
timestamp = int(tree.xpath('/xport/meta/start')[0].text)
step = int(tree.xpath('/xport/meta/step')[0].text)
for row in tree.xpath('/xport/data/row'):
for vindex, value in enumerate(row.findall('v')):
if value.text == 'NaN':
result[vindex]['data'].append({'x': timestamp, 'y': 0})
else:
result[vindex]['data'].append(
{'x': timestamp, 'y': float(value.text)}
)
timestamp += step
return result
class GraphicSet(object):
"""A set of graphics."""
domain_selector = False
title = None
_graphics = []
def __init__(self, instances=None):
if instances is None:
instances = []
self.__ginstances = instances
@property
def html_id(self):
return self.__class__.__name__.lower()
@property
def graphics(self):
if not self.__ginstances:
self.__ginstances = [graphic() for graphic in self._graphics]
return self.__ginstances
def get_graphic_names(self):
return [graphic.display_name for graphic in self._graphics]
def get_file_name(self, request):
"""Return database file name."""
return self.file_name
def export(self, rrdfile, start, end):
result = {}
for graph in self.graphics:
result[graph.display_name] = {
"title": six.text_type(graph.title),
"curves": graph.export(rrdfile, start, end)
}
return result
class AverageTraffic(Graphic):
"""Average traffic."""
title = ugettext_lazy('Average traffic (msgs/min)')
# Curve definitions
sent = Curve("sent", "lawngreen", ugettext_lazy("sent messages"))
recv = Curve("recv", "steelblue", ugettext_lazy("received messages"))
bounced = Curve("bounced", "yellow", ugettext_lazy("bounced messages"))
reject = Curve("reject", "tomato", ugettext_lazy("rejected messages"))
virus = Curve("virus", "orange", ugettext_lazy("virus messages"))
spam = Curve("spam", "silver", ugettext_lazy("spam messages"))
order = ["reject", "bounced", "recv", "sent", "virus", "spam"]
def __init__(self, greylist=False):
if greylist:
self.greylist = Curve(
"greylist", "dimgrey", ugettext_lazy("greylisted messages"))
self.order = [
"reject", "greylist", "bounced", "recv", "sent", "virus",
"spam"
]
super().__init__()
class AverageTrafficSize(Graphic):
"""Average traffic size."""
title = ugettext_lazy('Average normal traffic size (bytes/min)')
# Curve definitions
size_recv = Curve("size_recv", "orange", ugettext_lazy("received size"))
size_sent = Curve(
"size_sent", "mediumturquoise", ugettext_lazy("sent size")
)
class MailTraffic(GraphicSet):
"""Mail traffic graphic set."""
domain_selector = True
title = ugettext_lazy("Mail traffic")
_graphics = [AverageTraffic, AverageTrafficSize]
def __init__(self, greylist=False):
instances = [AverageTraffic(greylist), AverageTrafficSize()]
super().__init__(instances)
def _check_domain_access(self, user, pattern):
"""Check if an administrator can access a domain.
If a non super administrator asks for the global view, we give him
a view on the first domain he manage instead.
:return: a domain name (str) or None.
"""
if pattern in [None, "global"]:
if not user.is_superuser:
domains = admin_models.Domain.objects.get_for_admin(user)
if not domains.exists():
return None
return domains.first().name
return "global"
results = list(
chain(
admin_models.Domain.objects.filter(name__startswith=pattern),
admin_models.DomainAlias.objects.filter(
name__startswith=pattern)
)
)
if len(results) != 1:
return None
if not user.can_access(results[0]):
raise exceptions.PermDeniedException
return results[0].name
def get_file_name(self, request):
"""Retrieve file name according to user and args."""
searchq = request.GET.get("searchquery", None)
return self._check_domain_access(request.user, searchq)
class AccountCreationGraphic(Graphic):
"""Account creation over time."""
title = ugettext_lazy("Average account creation (account/hour)")
accounts = Curve(
"new_accounts", "steelblue", ugettext_lazy("New accounts"))
class AccountGraphicSet(GraphicSet):
"""A graphic set for accounts."""
file_name = "new_accounts"
title = ugettext_lazy("Accounts")
_graphics = [AccountCreationGraphic]
+38
View File
@@ -0,0 +1,38 @@
"""Modoboa stats signal handlers."""
from django.urls import reverse
from django.dispatch import receiver
from django.utils.translation import ugettext as _
from modoboa.admin import signals as admin_signals
from modoboa.core import signals as core_signals
from modoboa.parameters import tools as param_tools
from . import graphics
from . import signals
@receiver(core_signals.extra_user_menu_entries)
def menu(sender, location, user, **kwargs):
"""Return extra menu entry."""
if location != "top_menu" or user.role == "SimpleUsers":
return []
return [
{"name": "stats",
"label": _("Statistics"),
"url": reverse('maillog:fullindex')}
]
@receiver(signals.get_graph_sets)
def get_default_graphic_sets(sender, **kwargs):
"""Return graphic set."""
mail_traffic_gset = graphics.MailTraffic(
param_tools.get_global_parameter("greylist", raise_exception=False))
result = {
mail_traffic_gset.html_id: mail_traffic_gset
}
if kwargs.get("user").is_superuser:
account_gset = graphics.AccountGraphicSet()
result.update({account_gset.html_id: account_gset})
return result
+25
View File
@@ -0,0 +1,25 @@
# coding: utf-8
import sys
import time
def date_to_timestamp(timetuple):
"""Date conversion.
Returns a date and a time in seconds from the epoch.
:param list timetuple: list containing date
:return: an integer
"""
date = " ".join(
[("%d" % elem) if isinstance(elem, int) else elem
for elem in timetuple]
)
fmt = "%Y %m %d %H %M %S" \
if timetuple[1].isdigit() else "%Y %b %d %H %M %S"
try:
local = time.strptime(date, fmt)
except ValueError:
print >> sys.stderr, "Error: failed to convert date and time"
return 0
return int(time.mktime(local))
@@ -0,0 +1,178 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Miroslav Abrahám <miris@kunago.com>, 2013-2015
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2015-01-06 10:05+0000\n"
"Last-Translator: Miroslav Abrahám <miris@kunago.com>\n"
"Language-Team: Czech (Czech Republic) (http://www.transifex.com/projects/p/"
"modoboa/language/cs_CZ/)\n"
"Language: cs_CZ\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
#: forms.py:20
msgid "General"
msgstr "Obecné"
#: forms.py:23
msgid "Path to the log file"
msgstr "Cesta k souboru záznamů"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr ""
"Cesta k souboru záznamů, který se používá pro sběr statistických informací"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Adresář pro RRD soubory"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Cesta k adresáři, ve kterém budou ukládány RRD soubory"
#: forms.py:38
#, fuzzy
#| msgid "rejected messages"
msgid "Show greylisted messages"
msgstr "odmítnuté zprávy"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr ""
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Statistiky"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr ""
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "Průměrný provoz (zprávy/min)"
#: graphics.py:177
msgid "sent messages"
msgstr "odeslané zprávy"
#: graphics.py:178
msgid "received messages"
msgstr "přijaté zprávy"
#: graphics.py:179
msgid "bounced messages"
msgstr "nedoručené zprávy"
#: graphics.py:180
msgid "rejected messages"
msgstr "odmítnuté zprávy"
#: graphics.py:181
#, fuzzy
#| msgid "sent messages"
msgid "virus messages"
msgstr "odeslané zprávy"
#: graphics.py:182
#, fuzzy
#| msgid "sent messages"
msgid "spam messages"
msgstr "odeslané zprávy"
#: graphics.py:189
#, fuzzy
#| msgid "rejected messages"
msgid "greylisted messages"
msgstr "odmítnuté zprávy"
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "Průměrná velikost provozu (bajtů/min)"
#: graphics.py:203
msgid "received size"
msgstr "doručená velikost"
#: graphics.py:205
msgid "sent size"
msgstr "odeslaná velikost"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Provoz emailů"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr ""
#: graphics.py:261
msgid "New accounts"
msgstr ""
#: graphics.py:268
msgid "Accounts"
msgstr ""
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Grafické statistiky"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Hledat doménu"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Uložit"
#: views.py:33
msgid "No statistics available"
msgstr "Žádné statistiky nejsou dostupné"
#: views.py:40
msgid "Day"
msgstr "Den"
#: views.py:41
msgid "Week"
msgstr "Týden"
#: views.py:42
msgid "Month"
msgstr "Měsíc"
#: views.py:43
msgid "Year"
msgstr "Rok"
#: views.py:44
msgid "Custom"
msgstr "Vlastní"
#: views.py:63
msgid "Unknown graphic set"
msgstr "Nastaveno neznámé zobrazení"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Nastaveno neznámé zobrazení"
#: views.py:73
msgid "Bad custom period"
msgstr "Neplatně nastavený vlastní časový interval"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "Grafické statistiky emailového provozu s použitím RRDtool"
@@ -0,0 +1,24 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Miroslav Abrahám <miris@kunago.com>, 2013,2015
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2015-01-06 10:05+0000\n"
"Last-Translator: Miroslav Abrahám <miris@kunago.com>\n"
"Language-Team: Czech (Czech Republic) (http://www.transifex.com/projects/p/"
"modoboa/language/cs_CZ/)\n"
"Language: cs_CZ\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Vyhledat doménu"
@@ -0,0 +1,178 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Arvedui <arvedui@posteo.de>, 2014
# Patrick Koetter <p@state-of-mind.de>, 2010
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2014-12-03 11:02+0000\n"
"Last-Translator: Arvedui <arvedui@posteo.de>\n"
"Language-Team: German (http://www.transifex.com/projects/p/modoboa/language/"
"de/)\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:20
msgid "General"
msgstr "Allgemein"
#: forms.py:23
msgid "Path to the log file"
msgstr "Pfad zur Log-Datei"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "Pfad zur Log-Datei, um Statistiken zu sammeln"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Ablageverzeichnis für RRD-Dateien"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Pfad zum Verzeichnis in dem die RRD-Dateien abgelegt werden"
#: forms.py:38
#, fuzzy
#| msgid "rejected messages"
msgid "Show greylisted messages"
msgstr "Abgewiesene Nachrichten"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr ""
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Statistiken"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr ""
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "Durchschnittlicher Traffic (Nachrichten/min)"
#: graphics.py:177
msgid "sent messages"
msgstr "Gesendete Nachrichten"
#: graphics.py:178
msgid "received messages"
msgstr "Empfangene Nachrichten"
#: graphics.py:179
msgid "bounced messages"
msgstr "Zurückgeworfene Nachrichten"
#: graphics.py:180
msgid "rejected messages"
msgstr "Abgewiesene Nachrichten"
#: graphics.py:181
#, fuzzy
#| msgid "sent messages"
msgid "virus messages"
msgstr "Gesendete Nachrichten"
#: graphics.py:182
#, fuzzy
#| msgid "sent messages"
msgid "spam messages"
msgstr "Gesendete Nachrichten"
#: graphics.py:189
#, fuzzy
#| msgid "rejected messages"
msgid "greylisted messages"
msgstr "Abgewiesene Nachrichten"
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "Durchschnittliche Traffic-Menge (Bytes/min)"
#: graphics.py:203
msgid "received size"
msgstr "Empfangsgröße"
#: graphics.py:205
msgid "sent size"
msgstr "Versendegröße"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Mailverkehr"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr ""
#: graphics.py:261
msgid "New accounts"
msgstr ""
#: graphics.py:268
msgid "Accounts"
msgstr ""
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Grafische Statistiken"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Domain suchen"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Antworten"
#: views.py:33
msgid "No statistics available"
msgstr "Keine Statistik-Daten verfügbar"
#: views.py:40
msgid "Day"
msgstr "Tag"
#: views.py:41
msgid "Week"
msgstr "Woche"
#: views.py:42
msgid "Month"
msgstr "Monat"
#: views.py:43
msgid "Year"
msgstr "Jahr"
#: views.py:44
msgid "Custom"
msgstr "Benutzerdefiniert"
#: views.py:63
msgid "Unknown graphic set"
msgstr "Unbekanntes graphisches Set"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Unbekanntes graphisches Set"
#: views.py:73
msgid "Bad custom period"
msgstr "Ungültiger individueller Zeitraum"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "Grafische E-Mail-Statistik (setzt RRDtool ein)"
@@ -0,0 +1,25 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Arvedui <arvedui@posteo.de>, 2014
# Patrick Koetter <p@state-of-mind.de>, 2010
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2014-12-01 12:12+0000\n"
"Last-Translator: Arvedui <arvedui@posteo.de>\n"
"Language-Team: German (http://www.transifex.com/projects/p/modoboa/language/"
"de/)\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Domain suchen"
@@ -0,0 +1,176 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Giannis Kapetanakis <bilias@edu.physics.uoc.gr>, 2016
# Kostas Moumouris <moumouriskostas@gmail.com>, 2017
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2017-10-12 07:37+0000\n"
"Last-Translator: Kostas Moumouris <moumouriskostas@gmail.com>\n"
"Language-Team: Greek (Greece) (http://www.transifex.com/tonio/modoboa/"
"language/el_GR/)\n"
"Language: el_GR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:20
msgid "General"
msgstr "Γενικά"
#: forms.py:23
msgid "Path to the log file"
msgstr "Διαδρομή προς το αρχείο καταγραφής"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "Διαδρομή προς το αρχείο καταγραφής για την συλλογή στατιστικών"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Κατάλογος αρχείων για την αποθήκευση των αρχείων RRD"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Διαδρομή προς τον κατάλογο αρχείων για την αποθήκευση αρχείων RRD"
#: forms.py:38
msgid "Show greylisted messages"
msgstr "Εμφάνιση μηνυμάτων greylisted"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr ""
"Διαφοροποίηση μεταξύ σκληρών (hard) και μαλακών (soft) απορρίψεων "
"(greylisting)"
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Στατιστικά"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr "Αδυναμία εύρεσης του εκτελέσουμε rrdtool."
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "Μέσος όρος κίνησης (μηνύματα/λεπτό)"
#: graphics.py:177
msgid "sent messages"
msgstr "απεσταλμένα μηνύματα"
#: graphics.py:178
msgid "received messages"
msgstr "ληφθέντα μηνήματα"
#: graphics.py:179
msgid "bounced messages"
msgstr "Μηνύματα bounced "
#: graphics.py:180
msgid "rejected messages"
msgstr "απορριφθέντα μηνύματα"
#: graphics.py:181
msgid "virus messages"
msgstr ""
"Μηνύματα με ιούς \n"
" "
#: graphics.py:182
msgid "spam messages"
msgstr "Διαφημιστικά μηνύματα"
#: graphics.py:189
msgid "greylisted messages"
msgstr ""
"Μηνύματα που είναι greylisted\n"
" "
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "Μέσος όρος φυσιολογικού traffic (bytes/min) "
#: graphics.py:203
msgid "received size"
msgstr "Μέγεθος λαμβανόμενου"
#: graphics.py:205
msgid "sent size"
msgstr "μέγεθος αποστολής"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Κίνηση Mail"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr "Μέσος όρος δημιουργίας λογαριασμών (λογαριασμοί/ώρα)"
#: graphics.py:261
msgid "New accounts"
msgstr "Νέοι λογαριασμοί"
#: graphics.py:268
msgid "Accounts"
msgstr "Λογαριασμοί"
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Γραφικά στατιστικά"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Αναζήτηση ενός domain"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Εφαρμογή"
#: views.py:33
msgid "No statistics available"
msgstr "Δεν υπάρχουν διαθέσιμα στατιστικά"
#: views.py:40
msgid "Day"
msgstr "Ημέρα"
#: views.py:41
msgid "Week"
msgstr "Εβδομάδα"
#: views.py:42
msgid "Month"
msgstr "Μήνας"
#: views.py:43
msgid "Year"
msgstr "Έτος"
#: views.py:44
msgid "Custom"
msgstr "Προσαρμοσμένο"
#: views.py:63
msgid "Unknown graphic set"
msgstr "Άγνωστο σετ γραφικών"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Άγνωστο σετ γραφικών"
#: views.py:73
msgid "Bad custom period"
msgstr "Λάθος προσαρμοσμένη περίοδος"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "Γραφικά στατιστικά της κίνησης email με RRDtool"
@@ -0,0 +1,23 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Giannis Kapetanakis <bilias@edu.physics.uoc.gr>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2017-09-22 22:21+0000\n"
"Last-Translator: Giannis Kapetanakis <bilias@edu.physics.uoc.gr>\n"
"Language-Team: Greek (Greece) (http://www.transifex.com/tonio/modoboa/language/el_GR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: el_GR\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Αναζήτηση ενός domain"
@@ -0,0 +1,162 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: forms.py:20
msgid "General"
msgstr ""
#: forms.py:23
msgid "Path to the log file"
msgstr ""
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr ""
#: forms.py:30
msgid "Directory to store RRD files"
msgstr ""
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr ""
#: forms.py:38
msgid "Show greylisted messages"
msgstr ""
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr ""
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr ""
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr ""
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr ""
#: graphics.py:177
msgid "sent messages"
msgstr ""
#: graphics.py:178
msgid "received messages"
msgstr ""
#: graphics.py:179
msgid "bounced messages"
msgstr ""
#: graphics.py:180
msgid "rejected messages"
msgstr ""
#: graphics.py:181
msgid "virus messages"
msgstr ""
#: graphics.py:182
msgid "spam messages"
msgstr ""
#: graphics.py:189
msgid "greylisted messages"
msgstr ""
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr ""
#: graphics.py:203
msgid "received size"
msgstr ""
#: graphics.py:205
msgid "sent size"
msgstr ""
#: graphics.py:213
msgid "Mail traffic"
msgstr ""
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr ""
#: graphics.py:261
msgid "New accounts"
msgstr ""
#: graphics.py:268
msgid "Accounts"
msgstr ""
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr ""
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr ""
#: templates/maillog/index.html:77
msgid "Apply"
msgstr ""
#: views.py:33
msgid "No statistics available"
msgstr ""
#: views.py:40
msgid "Day"
msgstr ""
#: views.py:41
msgid "Week"
msgstr ""
#: views.py:42
msgid "Month"
msgstr ""
#: views.py:43
msgid "Year"
msgstr ""
#: views.py:44
msgid "Custom"
msgstr ""
#: views.py:63
msgid "Unknown graphic set"
msgstr ""
#: views.py:68
msgid "Unknown domain"
msgstr ""
#: views.py:73
msgid "Bad custom period"
msgstr ""
@@ -0,0 +1,22 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr ""
@@ -0,0 +1,171 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Carlos L <carlos.latorre.sanchez@openmailbox.org>, 2017
# Evilham <github@evilham.com>, 2017
# Pedro Gracia <lasarux@neuroomante.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2017-11-23 16:41+0000\n"
"Last-Translator: Evilham <github@evilham.com>\n"
"Language-Team: Spanish (http://www.transifex.com/tonio/modoboa/language/"
"es/)\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:20
msgid "General"
msgstr "General"
#: forms.py:23
msgid "Path to the log file"
msgstr "Ruta del fichero de log"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "Ruta al fichero de log usado para recolectar estadísticas"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Directorio para guardar los ficheros RRD"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Ruta al directorio dónde están almacenados los ficheros RRD"
#: forms.py:38
msgid "Show greylisted messages"
msgstr ""
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr ""
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Estadísticas"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr "Fallo al localizar el binario rrdtool"
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "Media del tráfico (msgs/min)"
#: graphics.py:177
msgid "sent messages"
msgstr "mensajes enviados"
#: graphics.py:178
msgid "received messages"
msgstr "mensajes recibidos"
#: graphics.py:179
msgid "bounced messages"
msgstr "mensajes rebotados"
#: graphics.py:180
msgid "rejected messages"
msgstr "mensajes bloqueados"
#: graphics.py:181
msgid "virus messages"
msgstr "mensajes con virus"
#: graphics.py:182
msgid "spam messages"
msgstr "Mensajes Basura"
#: graphics.py:189
msgid "greylisted messages"
msgstr ""
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "Media normal del tamaño del tráfico (bytes/min)"
#: graphics.py:203
msgid "received size"
msgstr "tamaño recibido"
#: graphics.py:205
msgid "sent size"
msgstr "tamaño enviado"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Tráfico de correo"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr "Creación promedio de cuentas (cuentas/hora)"
#: graphics.py:261
msgid "New accounts"
msgstr "Cuentas nuevos"
#: graphics.py:268
msgid "Accounts"
msgstr "Cuentas"
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Estadísticas gráficas"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Buscar un dominio"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Aplicar"
#: views.py:33
msgid "No statistics available"
msgstr "No hay estadísticas disponibles"
#: views.py:40
msgid "Day"
msgstr "Día"
#: views.py:41
msgid "Week"
msgstr "Semana"
#: views.py:42
msgid "Month"
msgstr "Mes"
#: views.py:43
msgid "Year"
msgstr "Año"
#: views.py:44
msgid "Custom"
msgstr "A medida"
#: views.py:63
msgid "Unknown graphic set"
msgstr "Conjunto gráfico desconocido"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Conjunto gráfico desconocido"
#: views.py:73
msgid "Bad custom period"
msgstr "Período elegido erróneo"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "Estadísticas gráficas del tráfico de emails usando RRDtool"
@@ -0,0 +1,24 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Pedro Gracia <lasarux@neuroomante.com>, 2011,2013
# Pedro Gracia <pedro.gracia@impulzia.com>, 2010-2011
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2017-09-22 09:57+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: Spanish (http://www.transifex.com/tonio/modoboa/language/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: es\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Buscar un dominio"
@@ -0,0 +1,170 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Antoine Nguyen <tonio@ngyn.org>, 2017
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2017-08-09 08:17+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: French (http://www.transifex.com/tonio/modoboa/language/fr/)\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: forms.py:20
msgid "General"
msgstr "Général"
#: forms.py:23
msgid "Path to the log file"
msgstr "Chemin d'accès vers le journal"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "Emplacement du log utilisé pour collecter les statistiques"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Répertoire où stocker les fichiers RRD"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Emplacement du répertoire de stockage des fichiers RRD"
#: forms.py:38
msgid "Show greylisted messages"
msgstr "Afficher les messages greylistés"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr "Différencie les rejets en douceur des rejets durs (greylisting)"
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Statistiques"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr "Impossible de trouver le binaire rrdtool"
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "Trafic moyen (msgs/min)"
#: graphics.py:177
msgid "sent messages"
msgstr "messages envoyés"
#: graphics.py:178
msgid "received messages"
msgstr "messages reçus"
#: graphics.py:179
msgid "bounced messages"
msgstr "messages non remis"
#: graphics.py:180
msgid "rejected messages"
msgstr "messages rejetés"
#: graphics.py:181
msgid "virus messages"
msgstr "messages de type virus"
#: graphics.py:182
msgid "spam messages"
msgstr "messages de type spam"
#: graphics.py:189
msgid "greylisted messages"
msgstr "Messages greylistés"
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "Taille moyenne du trafic normal (octets/min)"
#: graphics.py:203
msgid "received size"
msgstr "taille reçue"
#: graphics.py:205
msgid "sent size"
msgstr "taille envoyée"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Trafic messagerie"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr "Moyenne des créations de compte (compte/heure)"
#: graphics.py:261
msgid "New accounts"
msgstr "Nouveaux comptes"
#: graphics.py:268
msgid "Accounts"
msgstr "Comptes"
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Statistiques graphiques"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Chercher un domaine"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Appliquer"
#: views.py:33
msgid "No statistics available"
msgstr "Aucune statistique disponible"
#: views.py:40
msgid "Day"
msgstr "Jour"
#: views.py:41
msgid "Week"
msgstr "Semaine"
#: views.py:42
msgid "Month"
msgstr "Mois"
#: views.py:43
msgid "Year"
msgstr "Année"
#: views.py:44
msgid "Custom"
msgstr "Personnalisée"
#: views.py:63
msgid "Unknown graphic set"
msgstr "Jeu de graphiques inconnu"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Jeu de graphiques inconnu"
#: views.py:73
msgid "Bad custom period"
msgstr "Mauvaise période personnalisée"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr ""
#~ "Statistiques graphiques concernant le trafic des messages utilisant "
#~ "RRDtool"
@@ -0,0 +1,22 @@
# Modoboa french translation
# Copyright (C) 2009-2013
# This file is distributed under the same license as the Modoboa package.
# Antoine Nguyen <tonio@ngyn.org>, 2009-2013.
#
msgid ""
msgstr ""
"Project-Id-Version: modoboa-1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2011-01-07 10:00+0100\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: FR <tonio@ngyn.org>\n"
"Language: Français\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Checher un domaine"
@@ -0,0 +1,177 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Giancarlo Gaifas <lallo@artiemestieri.tn.it>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2013-12-23 00:56+0100\n"
"Last-Translator: Alberto Berti <alberto@metapensiero.it>\n"
"Language-Team: ITALIANO <LL@li.org>\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:20
msgid "General"
msgstr "Generale"
#: forms.py:23
msgid "Path to the log file"
msgstr "Percorso del file di log"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "Percorso del file di log utilizzato per raccogliere le statistiche"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Cartella dei file RRD"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Percorso della cartella dove sono memorizzati i file RRD"
#: forms.py:38
#, fuzzy
#| msgid "rejected messages"
msgid "Show greylisted messages"
msgstr "messaggi respinti"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr ""
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Statistiche"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr ""
#: graphics.py:174
#, fuzzy
msgid "Average traffic (msgs/min)"
msgstr "Dimensione del traffico normale medio"
#: graphics.py:177
msgid "sent messages"
msgstr "messaggi inviati"
#: graphics.py:178
msgid "received messages"
msgstr "messaggi ricevuti"
#: graphics.py:179
msgid "bounced messages"
msgstr "messaggi di rimbalzo"
#: graphics.py:180
msgid "rejected messages"
msgstr "messaggi respinti"
#: graphics.py:181
#, fuzzy
#| msgid "sent messages"
msgid "virus messages"
msgstr "messaggi inviati"
#: graphics.py:182
#, fuzzy
#| msgid "sent messages"
msgid "spam messages"
msgstr "messaggi inviati"
#: graphics.py:189
#, fuzzy
#| msgid "rejected messages"
msgid "greylisted messages"
msgstr "messaggi respinti"
#: graphics.py:200
#, fuzzy
msgid "Average normal traffic size (bytes/min)"
msgstr "Dimensione del traffico normale medio"
#: graphics.py:203
msgid "received size"
msgstr "dimensione di ricezione"
#: graphics.py:205
msgid "sent size"
msgstr "dimensione di spedizione"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Traffico mail"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr ""
#: graphics.py:261
msgid "New accounts"
msgstr ""
#: graphics.py:268
msgid "Accounts"
msgstr ""
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Grafico statistiche"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Ricerca un dominio"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Applica"
#: views.py:33
msgid "No statistics available"
msgstr "Non sono disponibili statistiche"
#: views.py:40
msgid "Day"
msgstr "Giorno"
#: views.py:41
msgid "Week"
msgstr "Settimana"
#: views.py:42
msgid "Month"
msgstr "Mese"
#: views.py:43
msgid "Year"
msgstr "Anno"
#: views.py:44
msgid "Custom"
msgstr ""
#: views.py:63
msgid "Unknown graphic set"
msgstr "Impostazione grafica sconosciuta"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Impostazione grafica sconosciuta"
#: views.py:73
msgid "Bad custom period"
msgstr "Periodo personalizzato sbagliato"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "Grafico delle statistiche sul traffico e-mail utilizzando RRDtool"
@@ -0,0 +1,22 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2013-12-23 00:58+0100\n"
"Last-Translator: Alberto Berti <alberto@metapensiero.it>\n"
"Language-Team: Italiano <LL@li.org>\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Cerca un dominio"
@@ -0,0 +1,179 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# cwatanab <chihiro.watanabe@live.jp>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2016-06-07 08:56+0000\n"
"Last-Translator: cwatanab <chihiro.watanabe@live.jp>\n"
"Language-Team: Japanese (Japan) (http://www.transifex.com/tonio/modoboa/"
"language/ja_JP/)\n"
"Language: ja_JP\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: forms.py:20
msgid "General"
msgstr "全般"
#: forms.py:23
msgid "Path to the log file"
msgstr "ログファイルへのパス"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "統計情報を収集するために使用されたログファイルへのパス"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "RRD ファイルを保管するためのディレクトリ"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "RRD ファイルが保管されたディレクトリへのパス"
#: forms.py:38
#, fuzzy
#| msgid "rejected messages"
msgid "Show greylisted messages"
msgstr "拒否メッセージ"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr ""
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "統計情報"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr ""
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "平均トラフィック (通/分)"
#: graphics.py:177
msgid "sent messages"
msgstr "送信メッセージ"
#: graphics.py:178
msgid "received messages"
msgstr "受信メッセージ"
#: graphics.py:179
msgid "bounced messages"
msgstr "バウンスメッセージ"
#: graphics.py:180
msgid "rejected messages"
msgstr "拒否メッセージ"
#: graphics.py:181
#, fuzzy
#| msgid "sent messages"
msgid "virus messages"
msgstr "送信メッセージ"
#: graphics.py:182
#, fuzzy
#| msgid "sent messages"
msgid "spam messages"
msgstr "送信メッセージ"
#: graphics.py:189
#, fuzzy
#| msgid "rejected messages"
msgid "greylisted messages"
msgstr "拒否メッセージ"
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "平均トラフィックサイズ (バイト/分)"
#: graphics.py:203
msgid "received size"
msgstr "受信サイズ"
#: graphics.py:205
msgid "sent size"
msgstr "送信サイズ"
#: graphics.py:213
msgid "Mail traffic"
msgstr "メールトラフィック"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr ""
#: graphics.py:261
msgid "New accounts"
msgstr ""
#: graphics.py:268
msgid "Accounts"
msgstr ""
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "グラフィカルな統計情報"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "ドメインを検索"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "適用"
#: views.py:33
msgid "No statistics available"
msgstr "統計情報がありません"
#: views.py:40
msgid "Day"
msgstr "日"
#: views.py:41
msgid "Week"
msgstr "週"
#: views.py:42
msgid "Month"
msgstr "月"
#: views.py:43
msgid "Year"
msgstr "年"
#: views.py:44
msgid "Custom"
msgstr "カスタム"
#: views.py:63
msgid "Unknown graphic set"
msgstr "不明なグラフィックセット"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "不明なグラフィックセット"
#: views.py:73
msgid "Bad custom period"
msgstr "カスタム期間が不正です"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr ""
#~ "RRDtool を使用して、電子メールトラフィックに関するグラフィカルな統計情報を"
#~ "表示します。"
@@ -0,0 +1,24 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# cwatanab <chihiro.watanabe@live.jp>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2016-06-07 07:16+0000\n"
"Last-Translator: cwatanab <chihiro.watanabe@live.jp>\n"
"Language-Team: Japanese (Japan) (http://www.transifex.com/tonio/modoboa/"
"language/ja_JP/)\n"
"Language: ja_JP\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "ドメインを検索"
@@ -0,0 +1,178 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Andrew <buddha@cryptolab.net>, 2014
# TuxBrother <vrijwilligerswerk@wij.rs>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2014-12-31 11:37+0000\n"
"Last-Translator: TuxBrother <vrijwilligerswerk@wij.rs>\n"
"Language-Team: Dutch (Netherlands) (http://www.transifex.com/projects/p/"
"modoboa/language/nl_NL/)\n"
"Language: nl_NL\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:20
msgid "General"
msgstr "Algemeen"
#: forms.py:23
msgid "Path to the log file"
msgstr "Locatie van logbestand"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "Locatie van logbestand gebruik om statistieken te maken"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Map om RRD bestanden op te slaan"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Locatie van map waar RRD bestanden staan"
#: forms.py:38
#, fuzzy
#| msgid "rejected messages"
msgid "Show greylisted messages"
msgstr "geweigerde berichten"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr ""
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Statistieken"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr ""
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "Gemiddeld verkeer per minuut (berichten)"
#: graphics.py:177
msgid "sent messages"
msgstr "verstuurde berichten"
#: graphics.py:178
msgid "received messages"
msgstr "ontvangen berichten"
#: graphics.py:179
msgid "bounced messages"
msgstr "geweigerde berichten"
#: graphics.py:180
msgid "rejected messages"
msgstr "geweigerde berichten"
#: graphics.py:181
#, fuzzy
#| msgid "sent messages"
msgid "virus messages"
msgstr "verstuurde berichten"
#: graphics.py:182
#, fuzzy
#| msgid "sent messages"
msgid "spam messages"
msgstr "verstuurde berichten"
#: graphics.py:189
#, fuzzy
#| msgid "rejected messages"
msgid "greylisted messages"
msgstr "geweigerde berichten"
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "Gemiddelde bandbreette per minuut (bytes)"
#: graphics.py:203
msgid "received size"
msgstr "ontvangen grootte"
#: graphics.py:205
msgid "sent size"
msgstr "verstuurde grootte"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Mailverkeer"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr ""
#: graphics.py:261
msgid "New accounts"
msgstr ""
#: graphics.py:268
msgid "Accounts"
msgstr ""
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Grafische statistieken"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Zoek een domein"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Toepassen"
#: views.py:33
msgid "No statistics available"
msgstr "Geen statistieken beschikbaar"
#: views.py:40
msgid "Day"
msgstr "Dag"
#: views.py:41
msgid "Week"
msgstr "Week"
#: views.py:42
msgid "Month"
msgstr "Maand"
#: views.py:43
msgid "Year"
msgstr "Jaar"
#: views.py:44
msgid "Custom"
msgstr "Aangepast"
#: views.py:63
msgid "Unknown graphic set"
msgstr "Onbekende grafische set"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Onbekende grafische set"
#: views.py:73
msgid "Bad custom period"
msgstr "Ongeldige aangepaste periode"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "Grafische statistieken over emailverkeer dmv. RRDtool"
@@ -0,0 +1,25 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# TuxBrother <vrijwilligerswerk@wij.rs>, 2014
# TuxBrother <vrijwilligerswerk@wij.rs>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2014-12-31 11:42+0000\n"
"Last-Translator: TuxBrother <vrijwilligerswerk@wij.rs>\n"
"Language-Team: Dutch (Netherlands) (http://www.transifex.com/projects/p/"
"modoboa/language/nl_NL/)\n"
"Language: nl_NL\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Zoek een domein"
@@ -0,0 +1,172 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# sin88 <sin@sin.waw.pl>, 2016
# Tomasz Proć <tomasz.proc@gmail.com>, 2017
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2017-12-01 16:06+0000\n"
"Last-Translator: Tomasz Proć <tomasz.proc@gmail.com>\n"
"Language-Team: Polish (Poland) (http://www.transifex.com/tonio/modoboa/"
"language/pl_PL/)\n"
"Language: pl_PL\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n"
"%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n"
"%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
#: forms.py:20
msgid "General"
msgstr "Ogólne"
#: forms.py:23
msgid "Path to the log file"
msgstr "Ścieżka do pliku z logiem"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "Sćieżka do pliku z logiem dla colect "
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Katalog do przechowywania plików RRD"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Katalog gdzie przechowywane są pliki RRD"
#: forms.py:38
msgid "Show greylisted messages"
msgstr "Pokaż greylistowane wiadomości"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr "Rozróżniaj twarde i miękkie odrzuty (greylisting)"
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Statystyki"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr "Nie znaleziono binarki rrdtool."
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "Średni ruch (wiadomości/minutę)"
#: graphics.py:177
msgid "sent messages"
msgstr "Wysłane wiadomości"
#: graphics.py:178
msgid "received messages"
msgstr "Odebrane wiadomości"
#: graphics.py:179
msgid "bounced messages"
msgstr "Odbite wiadomości"
#: graphics.py:180
msgid "rejected messages"
msgstr "Odrzucone wiadomości"
#: graphics.py:181
msgid "virus messages"
msgstr "wiadomości zawirusowane"
#: graphics.py:182
msgid "spam messages"
msgstr "wiadomości spam"
#: graphics.py:189
msgid "greylisted messages"
msgstr "wiadomości opóźnione (greylisting)"
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "Średnia normalna wielkość ruchu (bajtów/min)"
#: graphics.py:203
msgid "received size"
msgstr "Ilość odebranych danych"
#: graphics.py:205
msgid "sent size"
msgstr "Ilość wysłanych danych"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Ruch e-mail"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr "Średnia ilość tworzonych kont (konto/godzina)"
#: graphics.py:261
msgid "New accounts"
msgstr "Nowe konta"
#: graphics.py:268
msgid "Accounts"
msgstr "Konta"
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Graficzne statytyki"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Wyszukaj domenę"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Zastosuj"
#: views.py:33
msgid "No statistics available"
msgstr "Brak dostępnych statysty"
#: views.py:40
msgid "Day"
msgstr "Dzień"
#: views.py:41
msgid "Week"
msgstr "Tydzień"
#: views.py:42
msgid "Month"
msgstr "Miesiąc"
#: views.py:43
msgid "Year"
msgstr "Rok"
#: views.py:44
msgid "Custom"
msgstr "Własne"
#: views.py:63
msgid "Unknown graphic set"
msgstr "Unknown graphic set"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Unknown graphic set"
#: views.py:73
msgid "Bad custom period"
msgstr "Nieprawudłowy przedział czasowy"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "Graficzne statystyki wiadomości z wykorzystaniem "
@@ -0,0 +1,23 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# sin88 <sin@sin.waw.pl>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2017-09-22 09:57+0000\n"
"Last-Translator: sin88 <sin@sin.waw.pl>\n"
"Language-Team: Polish (Poland) (http://www.transifex.com/tonio/modoboa/language/pl_PL/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: pl_PL\n"
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Wyszukaj domenę"
@@ -0,0 +1,179 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# csmk, 2014
# Paulino Michelazzo <paulino@michelazzo.com.br>, 2014
# Rafael Barretto Alves <ch3yd@hotmail.com>, 2013
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2014-12-13 09:10+0000\n"
"Last-Translator: Paulino Michelazzo <paulino@michelazzo.com.br>\n"
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/"
"modoboa/language/pt_BR/)\n"
"Language: pt_BR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: forms.py:20
msgid "General"
msgstr "Geral"
#: forms.py:23
msgid "Path to the log file"
msgstr "Caminho para o arquivo de log"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "Caminho para o arquivo de log usado para coletar estatísticas"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Diretório para armazenar arquivos RRD"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Caminho para o diretório onde os arquivos RRD são armazenados"
#: forms.py:38
#, fuzzy
#| msgid "rejected messages"
msgid "Show greylisted messages"
msgstr "mensagens rejeitadas"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr ""
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Estatísticas"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr ""
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "Tráfego médio (msgs/min)"
#: graphics.py:177
msgid "sent messages"
msgstr "mensagens enviadas"
#: graphics.py:178
msgid "received messages"
msgstr "mensagens recebidas"
#: graphics.py:179
msgid "bounced messages"
msgstr "mensagens devolvidas"
#: graphics.py:180
msgid "rejected messages"
msgstr "mensagens rejeitadas"
#: graphics.py:181
#, fuzzy
#| msgid "sent messages"
msgid "virus messages"
msgstr "mensagens enviadas"
#: graphics.py:182
#, fuzzy
#| msgid "sent messages"
msgid "spam messages"
msgstr "mensagens enviadas"
#: graphics.py:189
#, fuzzy
#| msgid "rejected messages"
msgid "greylisted messages"
msgstr "mensagens rejeitadas"
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "Tamanho médio de tráfego (bytes/min)"
#: graphics.py:203
msgid "received size"
msgstr "tamanho recebido"
#: graphics.py:205
msgid "sent size"
msgstr "tamanho enviado"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Tráfego de e-mail"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr ""
#: graphics.py:261
msgid "New accounts"
msgstr ""
#: graphics.py:268
msgid "Accounts"
msgstr ""
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Estatísticas gráficas"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Buscar um domínio"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Aplicar"
#: views.py:33
msgid "No statistics available"
msgstr "Não há estatísticas disponíveis"
#: views.py:40
msgid "Day"
msgstr "Dia"
#: views.py:41
msgid "Week"
msgstr "Semana"
#: views.py:42
msgid "Month"
msgstr "Mês"
#: views.py:43
msgid "Year"
msgstr "Ano"
#: views.py:44
msgid "Custom"
msgstr "Customizado"
#: views.py:63
msgid "Unknown graphic set"
msgstr "Conjunto gráfico desconhecido"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Conjunto gráfico desconhecido"
#: views.py:73
msgid "Bad custom period"
msgstr "Período customizado inválido"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "Estatísticas gráficas sobre o tráfego de e-mails usando RRDtool"
@@ -0,0 +1,24 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Paulino Michelazzo <paulino@michelazzo.com.br>, 2014
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2014-12-13 09:14+0000\n"
"Last-Translator: Paulino Michelazzo <paulino@michelazzo.com.br>\n"
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/projects/p/"
"modoboa/language/pt_BR/)\n"
"Language: pt_BR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Buscar um domínio"
@@ -0,0 +1,182 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Damien Duponchelle <dduponchelle@gmail.com>, 2013
# lusitan <lusitan@hushmail.com>, 2013
# Mike C. <miguelmclara@gmail.com>, 2012
# Mike C. <miguelmclara@gmail.com>, 2013-2014
# Sandra Ribeiro <sandrarib@gmail.com>, 2012-2013
# Sandra Ribeiro <sandrarib@gmail.com>, 2012
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2014-12-29 12:51+0000\n"
"Last-Translator: Mike C. <miguelmclara@gmail.com>\n"
"Language-Team: Portuguese (Portugal) (http://www.transifex.com/projects/p/"
"modoboa/language/pt_PT/)\n"
"Language: pt_PT\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:20
msgid "General"
msgstr "Geral"
#: forms.py:23
msgid "Path to the log file"
msgstr "Caminho para o ficheiro log"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "Caminho para o ficheiro de log usado para recolher as estatísticas"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Diretório para armazenar os ficheiros RRD"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Caminho para o diretório onde os ficheiros RRD são guardados"
#: forms.py:38
#, fuzzy
#| msgid "rejected messages"
msgid "Show greylisted messages"
msgstr "mensagens rejeitadas"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr ""
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Estatísticas"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr ""
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "Trafego em média (msgs/min)"
#: graphics.py:177
msgid "sent messages"
msgstr "mensagens enviadas"
#: graphics.py:178
msgid "received messages"
msgstr "mensagens recebidas"
#: graphics.py:179
msgid "bounced messages"
msgstr "mensagens devolvidas"
#: graphics.py:180
msgid "rejected messages"
msgstr "mensagens rejeitadas"
#: graphics.py:181
#, fuzzy
#| msgid "sent messages"
msgid "virus messages"
msgstr "mensagens enviadas"
#: graphics.py:182
#, fuzzy
#| msgid "sent messages"
msgid "spam messages"
msgstr "mensagens enviadas"
#: graphics.py:189
#, fuzzy
#| msgid "rejected messages"
msgid "greylisted messages"
msgstr "mensagens rejeitadas"
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "Tráfego em média normal por tamanho (bytes/min)"
#: graphics.py:203
msgid "received size"
msgstr "tamanho recebido"
#: graphics.py:205
msgid "sent size"
msgstr "tamanho enviado"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Tráfego de correio"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr ""
#: graphics.py:261
msgid "New accounts"
msgstr ""
#: graphics.py:268
msgid "Accounts"
msgstr ""
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Estatísticas gráficas"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Procurar um domínio"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Aplicar"
#: views.py:33
msgid "No statistics available"
msgstr "Não há estatísticas disponíveis"
#: views.py:40
msgid "Day"
msgstr "Dia"
#: views.py:41
msgid "Week"
msgstr "Semana"
#: views.py:42
msgid "Month"
msgstr "Mês"
#: views.py:43
msgid "Year"
msgstr "Ano"
#: views.py:44
msgid "Custom"
msgstr "Personalizado"
#: views.py:63
msgid "Unknown graphic set"
msgstr "Conjunto de gráficos desconhecido"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Conjunto de gráficos desconhecido"
#: views.py:73
msgid "Bad custom period"
msgstr "Período personalizado inválido"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "Estatísticas gráficas sobre tráfego de email usando RRDtool"
@@ -0,0 +1,29 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# lusitan <lusitan@hushmail.com>, 2013
# lusitan <lusitan@hushmail.com>, 2013
# Mike C. <miguelmclara@gmail.com>, 2012
# Mike C. <miguelmclara@gmail.com>, 2012
# Mike C. <miguelmclara@gmail.com>, 2014
# Sandra Ribeiro <sandrarib@gmail.com>, 2013
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2014-12-29 12:08+0000\n"
"Last-Translator: Mike C. <miguelmclara@gmail.com>\n"
"Language-Team: Portuguese (Portugal) (http://www.transifex.com/projects/p/"
"modoboa/language/pt_PT/)\n"
"Language: pt_PT\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Pesquisar domínio"
@@ -0,0 +1,170 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Andrei-Ilie Olteanu <andrei@flashsoft.ro>, 2018
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2018-06-12 15:03+0000\n"
"Last-Translator: Andrei-Ilie Olteanu <andrei@flashsoft.ro>\n"
"Language-Team: Romanian (Romania) (http://www.transifex.com/tonio/modoboa/"
"language/ro_RO/)\n"
"Language: ro_RO\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?"
"2:1));\n"
#: forms.py:20
msgid "General"
msgstr "General"
#: forms.py:23
msgid "Path to the log file"
msgstr "Calea către fișierul de log"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "Calea către fișierul de log în care se colectează statistici"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Directorul în care se stochează fisierele RRD"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Calea către directorul în care se stochează fisierele RRD"
#: forms.py:38
msgid "Show greylisted messages"
msgstr "Arată mesajele suspecte"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr "Diferențiază între mesjale rejectate hard și soft (suspecte)"
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Statistici"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr "Nu s-a gasit binarul rrdtool"
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "Media traficului (mesaje/min)"
#: graphics.py:177
msgid "sent messages"
msgstr "mesaje trimise"
#: graphics.py:178
msgid "received messages"
msgstr "mesaje primite "
#: graphics.py:179
msgid "bounced messages"
msgstr "mesaje returnate"
#: graphics.py:180
msgid "rejected messages"
msgstr "mesaje rejectate"
#: graphics.py:181
msgid "virus messages"
msgstr "mesaje cu virus"
#: graphics.py:182
msgid "spam messages"
msgstr "mesaje spam"
#: graphics.py:189
msgid "greylisted messages"
msgstr "mesaje suspecte"
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "Media de trafic (octecți/minut)"
#: graphics.py:203
msgid "received size"
msgstr "mărime pentru primite"
#: graphics.py:205
msgid "sent size"
msgstr "mărime pentru trimise"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Trafic Email"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr "Media creări de conturi (cont/oră)"
#: graphics.py:261
msgid "New accounts"
msgstr "Conturi noi"
#: graphics.py:268
msgid "Accounts"
msgstr "Conturi"
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Statistici grafice"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Cauta un domeniu"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Aplică"
#: views.py:33
msgid "No statistics available"
msgstr "Nu sunt disponibile statistici"
#: views.py:40
msgid "Day"
msgstr "Zi"
#: views.py:41
msgid "Week"
msgstr "Săptămană"
#: views.py:42
msgid "Month"
msgstr "Lună"
#: views.py:43
msgid "Year"
msgstr "An"
#: views.py:44
msgid "Custom"
msgstr "Personalizat"
#: views.py:63
msgid "Unknown graphic set"
msgstr "Set grafic necunoscut"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Set grafic necunoscut"
#: views.py:73
msgid "Bad custom period"
msgstr "Perioada personalizată invalidă"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "Statistici grafice despre traficul pe email folosind RRDtool"
@@ -0,0 +1,23 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Andrei-Ilie Olteanu <andrei@flashsoft.ro>, 2018
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2018-06-12 15:04+0000\n"
"Last-Translator: Andrei-Ilie Olteanu <andrei@flashsoft.ro>\n"
"Language-Team: Romanian (Romania) (http://www.transifex.com/tonio/modoboa/language/ro_RO/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ro_RO\n"
"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Cauta un domeniu"
@@ -0,0 +1,179 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2013-12-03 09:35+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: Russian (http://www.transifex.com/projects/p/modoboa/language/"
"ru/)\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
#: forms.py:20
msgid "General"
msgstr "Основные"
#: forms.py:23
msgid "Path to the log file"
msgstr "Путь к лог файлу"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "Путь к лог файлу для сбора статистики"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Папка для сохранения RRD файлов"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Путь к директории для сохранения RRD файлов"
#: forms.py:38
#, fuzzy
#| msgid "rejected messages"
msgid "Show greylisted messages"
msgstr "Отвергнутые сообщения"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr ""
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Статистика"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr ""
#: graphics.py:174
#, fuzzy
msgid "Average traffic (msgs/min)"
msgstr "Средний размер траффика"
#: graphics.py:177
msgid "sent messages"
msgstr "Отправлено сообщений"
#: graphics.py:178
msgid "received messages"
msgstr "Принято сообщений"
#: graphics.py:179
msgid "bounced messages"
msgstr "Возвращенные сообщения"
#: graphics.py:180
msgid "rejected messages"
msgstr "Отвергнутые сообщения"
#: graphics.py:181
#, fuzzy
#| msgid "sent messages"
msgid "virus messages"
msgstr "Отправлено сообщений"
#: graphics.py:182
#, fuzzy
#| msgid "sent messages"
msgid "spam messages"
msgstr "Отправлено сообщений"
#: graphics.py:189
#, fuzzy
#| msgid "rejected messages"
msgid "greylisted messages"
msgstr "Отвергнутые сообщения"
#: graphics.py:200
#, fuzzy
msgid "Average normal traffic size (bytes/min)"
msgstr "Средний размер траффика"
#: graphics.py:203
msgid "received size"
msgstr "Принято"
#: graphics.py:205
msgid "sent size"
msgstr "Отправлено"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Почтовый траффик"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr ""
#: graphics.py:261
msgid "New accounts"
msgstr ""
#: graphics.py:268
msgid "Accounts"
msgstr ""
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Графическая статистика"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Искать домен"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Применить"
#: views.py:33
msgid "No statistics available"
msgstr "Статистика не доступна"
#: views.py:40
msgid "Day"
msgstr "День"
#: views.py:41
msgid "Week"
msgstr "Неделя"
#: views.py:42
msgid "Month"
msgstr "Месяц"
#: views.py:43
msgid "Year"
msgstr "Год"
#: views.py:44
msgid "Custom"
msgstr ""
#: views.py:63
msgid "Unknown graphic set"
msgstr "Неизвестный графический набор "
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Неизвестный графический набор "
#: views.py:73
msgid "Bad custom period"
msgstr "Не верный выбор периода"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "Графическая статистика о почтовом траффика использует RRDtool"
@@ -0,0 +1,24 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2013-12-03 09:35+0000\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: Russian (http://www.transifex.com/projects/p/modoboa/language/"
"ru/)\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Найти домен"
@@ -0,0 +1,179 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Martin Persson <martin.jens.persson@gmail.com>, 2014
# Olle Gustafsson <olle@dalnix.se>, 2013
# Olle Gustafsson <olle@dalnix.se>, 2013,2015
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2015-01-13 15:18+0000\n"
"Last-Translator: Olle Gustafsson <olle@dalnix.se>\n"
"Language-Team: Swedish (http://www.transifex.com/projects/p/modoboa/language/"
"sv/)\n"
"Language: sv\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: forms.py:20
msgid "General"
msgstr "Generellt"
#: forms.py:23
msgid "Path to the log file"
msgstr "Sökväg till loggfil"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "Sökväg till loggfil som används för att samla in statistik"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "Katalog för lagring av RRD filer"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "Sökväg till katalog där RRD filer lagras"
#: forms.py:38
#, fuzzy
#| msgid "rejected messages"
msgid "Show greylisted messages"
msgstr "avvisade meddelanden"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr ""
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "Statistik"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr ""
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "Genomsnittlig trafik (meddelanden/min)"
#: graphics.py:177
msgid "sent messages"
msgstr "skickade meddelanden"
#: graphics.py:178
msgid "received messages"
msgstr "mottagna meddelande"
#: graphics.py:179
msgid "bounced messages"
msgstr "studsade meddelanden"
#: graphics.py:180
msgid "rejected messages"
msgstr "avvisade meddelanden"
#: graphics.py:181
#, fuzzy
#| msgid "sent messages"
msgid "virus messages"
msgstr "skickade meddelanden"
#: graphics.py:182
#, fuzzy
#| msgid "sent messages"
msgid "spam messages"
msgstr "skickade meddelanden"
#: graphics.py:189
#, fuzzy
#| msgid "rejected messages"
msgid "greylisted messages"
msgstr "avvisade meddelanden"
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "Genomsnittlig normal trafik (bytes/min)"
#: graphics.py:203
msgid "received size"
msgstr "mottagen storlek"
#: graphics.py:205
msgid "sent size"
msgstr "sänd storlek"
#: graphics.py:213
msgid "Mail traffic"
msgstr "Mail trafik"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr ""
#: graphics.py:261
msgid "New accounts"
msgstr ""
#: graphics.py:268
msgid "Accounts"
msgstr ""
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "Grafisk statistik"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "Sök en domän"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "Applicera"
#: views.py:33
msgid "No statistics available"
msgstr "Ingen statistik tillgänglig"
#: views.py:40
msgid "Day"
msgstr "Dag"
#: views.py:41
msgid "Week"
msgstr "Vecka"
#: views.py:42
msgid "Month"
msgstr "Månad"
#: views.py:43
msgid "Year"
msgstr "År"
#: views.py:44
msgid "Custom"
msgstr "Anpassad"
#: views.py:63
msgid "Unknown graphic set"
msgstr "Okänt grafisk uppsättning"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "Okänt grafisk uppsättning"
#: views.py:73
msgid "Bad custom period"
msgstr "Ogiltig anpassad tid"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "Grafisk statistik om e-post trafik med hjälp av RRDtool"
@@ -0,0 +1,25 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Olle Gustafsson <olle@dalnix.se>, 2013
# Olle Gustafsson <olle@dalnix.se>, 2013,2015
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2015-01-13 15:21+0000\n"
"Last-Translator: Olle Gustafsson <olle@dalnix.se>\n"
"Language-Team: Swedish (http://www.transifex.com/projects/p/modoboa/language/"
"sv/)\n"
"Language: sv\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "Sök domän"
@@ -0,0 +1,170 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# akong <akong@aspa.idv.tw>, 2018
# Radium <ztl8702@126.com>, 2017
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-17 11:24+0200\n"
"PO-Revision-Date: 2018-06-28 09:01+0000\n"
"Last-Translator: akong <akong@aspa.idv.tw>\n"
"Language-Team: Chinese (Taiwan) (http://www.transifex.com/tonio/modoboa/"
"language/zh_TW/)\n"
"Language: zh_TW\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: forms.py:20
msgid "General"
msgstr "一般"
#: forms.py:23
msgid "Path to the log file"
msgstr "日誌檔的路徑"
#: forms.py:25
msgid "Path to log file used to collect statistics"
msgstr "日誌檔的路徑用於蒐集狀態"
#: forms.py:30
msgid "Directory to store RRD files"
msgstr "儲存 RRD 檔案的目錄"
#: forms.py:33
msgid "Path to directory where RRD files are stored"
msgstr "RRD 檔案已儲存到目錄路徑"
#: forms.py:38
msgid "Show greylisted messages"
msgstr "顯示灰名單郵件"
#: forms.py:41
msgid "Differentiate between hard and soft rejects (greylisting)"
msgstr "區分在硬的退件跟軟的退件之間 (灰名單)"
#: forms.py:59 handlers.py:22
msgid "Statistics"
msgstr "統計"
#: graphics.py:95
msgid "Failed to locate rrdtool binary."
msgstr "指定 rrdtools 位置失敗。"
#: graphics.py:174
msgid "Average traffic (msgs/min)"
msgstr "平均流量 (郵件數/分鐘)"
#: graphics.py:177
msgid "sent messages"
msgstr "已發訊息"
#: graphics.py:178
msgid "received messages"
msgstr "收到的訊息"
#: graphics.py:179
msgid "bounced messages"
msgstr "已退回郵件"
#: graphics.py:180
msgid "rejected messages"
msgstr "已拒絕郵件"
#: graphics.py:181
msgid "virus messages"
msgstr "病毒郵件"
#: graphics.py:182
msgid "spam messages"
msgstr "垃圾郵件"
#: graphics.py:189
msgid "greylisted messages"
msgstr "灰名單郵件"
#: graphics.py:200
msgid "Average normal traffic size (bytes/min)"
msgstr "平均流量大小 (位元組/分鐘)"
#: graphics.py:203
msgid "received size"
msgstr "已接收大小"
#: graphics.py:205
msgid "sent size"
msgstr "寄送大小"
#: graphics.py:213
msgid "Mail traffic"
msgstr "郵件流量"
#: graphics.py:258
msgid "Average account creation (account/hour)"
msgstr "建立帳號平均值 (帳號/小時)"
#: graphics.py:261
msgid "New accounts"
msgstr "新帳號"
#: graphics.py:268
msgid "Accounts"
msgstr "帳號"
#: templates/maillog/index.html:4
msgid "Graphical statistics"
msgstr "圖形狀態"
#: templates/maillog/index.html:44
msgid "Search a domain"
msgstr "搜尋網域"
#: templates/maillog/index.html:77
msgid "Apply"
msgstr "套用"
#: views.py:33
msgid "No statistics available"
msgstr "沒有可用的狀態"
#: views.py:40
msgid "Day"
msgstr "日"
#: views.py:41
msgid "Week"
msgstr "周"
#: views.py:42
msgid "Month"
msgstr "月"
#: views.py:43
msgid "Year"
msgstr "年"
#: views.py:44
msgid "Custom"
msgstr "自訂"
#: views.py:63
msgid "Unknown graphic set"
msgstr "未知圖形設定"
#: views.py:68
#, fuzzy
#| msgid "Unknown graphic set"
msgid "Unknown domain"
msgstr "未知圖形設定"
#: views.py:73
msgid "Bad custom period"
msgstr "錯誤的自訂期間"
#~ msgid "Graphical statistics about emails traffic using RRDtool"
#~ msgstr "有關郵件流量的圖形狀態表是使用 RRDtool"
@@ -0,0 +1,23 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
# Radium <ztl8702@126.com>, 2017
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-03-03 09:37+0100\n"
"PO-Revision-Date: 2017-09-23 14:31+0000\n"
"Last-Translator: Radium <ztl8702@126.com>\n"
"Language-Team: Chinese (Taiwan) (http://www.transifex.com/tonio/modoboa/language/zh_TW/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_TW\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: static/modoboa_stats/js/stats.js:43
msgid "Search a domain"
msgstr "搜尋一個網域"
@@ -0,0 +1,632 @@
# coding: utf-8
"""
Postfix log parser.
This scripts parses a log file produced by postfix (or using the same
format). It looks for predefined events and build statistics about
their occurence rate.
At the, somes default graphics are generated using the grapher module.
(see grapher.py)
Predefined events are:
* Per domain sent/received messages,
* Per domain received bad messages (bounced, reject for now),
* Per domain sent/received traffics size,
* Global consolidation of all previous events.
"""
from datetime import datetime
import io
import os
import re
import sys
import time
import rrdtool
from django.core.management.base import BaseCommand
from django.db.models import Q
from django.utils import timezone
from modoboa.admin.models import Domain
from modoboa.parameters import tools as param_tools
from modoboa.lib.email_utils import split_mailbox
from ... import lib
from ... import models
rrdstep = 60
xpoints = 540
points_per_sample = 3
variables = ["sent", "recv", "bounced", "reject", "spam", "virus",
"size_sent", "size_recv"]
class LogParser:
def __init__(self, options, workdir, year=None, greylist=False):
"""Constructor."""
self.logfile = options["logfile"]
self.debug = options["debug"]
self.verbose = options["verbose"]
try:
self.f = io.open(self.logfile, encoding="utf-8")
except IOError as errno:
self._dprint("%s" % errno)
sys.exit(1)
self.workdir = workdir
self.__year = year
self.cfs = ["AVERAGE", "MAX"]
curtime = time.localtime()
if not self.__year:
self.__year = curtime.tm_year
self.curmonth = curtime.tm_mon
self.data = {"global": {}}
self.domains = []
self._load_domain_list()
self.workdict = {}
self.lupdates = {}
# set up regular expression
self._date_expressions = [
r"(?P<month>\w+)\s+(?P<day>\d+)\s+(?P<hour>\d+):(?P<min>\d+):(?P<sec>\d+)(?P<eol>.*)", # noqa
r"(?P<year>\d+)-(?P<month>\d+)-(?P<day>\d+)T(?P<hour>\d+):(?P<min>\d+):(?P<sec>\d+)\.\d+\+\d+:\d+(?P<eol>.*)" # noqa
]
self._date_expressions = [
re.compile(v) for v in self._date_expressions]
self.date_expr = None
self._regex = {
"line": r"\s+([-\w\.]+)\s+(\w+)/?(\w*)[[](\d+)[]]:\s+(.*)",
"id": r"(\w+): (.*)",
"reject": r"reject: .*from=<.*>,? to=<[^@]+@([^>]+)>",
"message-id": r"message-id=<([^>]*)>",
"from+size": r"from=<([^>]*)>, size=(\d+)",
"to+status": r"to=<([^>]*)>.*status=(\S+)",
"orig_to": r"orig_to=<([^>]*)>.*",
"amavis": r"(?P<result>INFECTED|SPAM|SPAMMY) .* <[^>]+> -> <[^@]+@(?P<domain>[^>]+)>.*", # noqa
"rmilter_line": r"<(?P<hash>[0-9a-f]{10})>; (?P<line>.*)",
"rmilter_msg_done": r"msg done: queue_id: <(?P<queue_id>[^>]+)>; message id: <(?P<message_id>[^>]+)>.*; from: <(?P<from>[^>]+)>; rcpt: <(?P<rcpt>[^>]+)>.*; spam scan: (?P<action>[^;]+); virus scan:", # noqa
"rmilter_spam": r"mlfi_eom: (rejecting spam|add spam header to message according to spamd action)", # noqa
"rmilter_virus": r"mlfi_eom:.* virus found",
"rmilter_greylist": (
r"GREYLIST\([0-9]+\.[0-9]{2}\)\[greylisted[^\]]*\]")
}
self._regex = {k: re.compile(v) for k, v in self._regex.items()}
self._srs_regex = {
"detect_srs": "^SRS[01][+-=]",
"reverse_srs0": r"^SRS0[+-=]\S+=\S{2}=(\S+)=(\S+)\@\S+$",
"reverse_srs1": r"^SRS1[+-=]\S+=\S+==\S+=\S{2}=(\S+)=(\S+)\@\S+$"
}
self._srs_regex = {
k: re.compile(v, re.IGNORECASE) for k, v in self._srs_regex.items()
}
self.greylist = greylist
if greylist:
variables.insert(4, "greylist")
self._dprint("[settings] greylisting enabled")
self._prev_se = -1
self._prev_mi = -1
self._prev_ho = -1
self.cur_t = 0
def _load_domain_list(self):
"""Load the list of allowed domains."""
for dom in Domain.objects.all():
domname = str(dom.name)
self.domains += [domname]
self.data[domname] = {}
# Also add alias domains
for alias in dom.domainalias_set.all():
aliasname = str(alias.name)
self.domains += [aliasname]
self.data[aliasname] = {}
def _dprint(self, msg):
"""Print a debug message if required.
:param str msg: debug message
"""
if not self.debug:
return
print(msg)
def _parse_date(self, line):
"""Try to match a date inside :kw:`line` and to convert it to
a timestamp.
We try different date format until we find valid one. We then
store it for future use.
:param str line: a log entry
:return: the remaining part of the line or None
"""
match = None
if self.date_expr is None:
for expr in self._date_expressions:
match = expr.match(line)
if match is not None:
self.date_expr = expr
break
else:
match = self.date_expr.match(line)
if match is None:
return None
ho = match.group("hour")
mi = match.group("min")
se = match.group("sec")
mo = match.group("month")
da = match.group("day")
try:
ye = match.group("year")
except IndexError:
ye = self.year(mo)
# Keep original timestamp
self.orig_ts = lib.date_to_timestamp([ye, mo, da, ho, mi, se])
# Now get the current period (based on rrdstep)
se = int(int(se) / rrdstep) # rrd step is one-minute => se = 0
if self._prev_se != se or self._prev_mi != mi or self._prev_ho != ho:
self.cur_t = lib.date_to_timestamp([ye, mo, da, ho, mi, se])
self.cur_t = self.cur_t - self.cur_t % rrdstep
self._prev_mi = mi
self._prev_ho = ho
self._prev_se = se
return match.group("eol")
def init_rrd(self, fname, m):
"""init_rrd.
Set-up Data Sources (DS)
Set-up Round Robin Archives (RRA):
- day,week,month and year archives
- 2 types : AVERAGE and MAX
parameter : start time
return : last epoch recorded
"""
ds_type = "ABSOLUTE"
rows = xpoints / points_per_sample
realrows = int(rows * 1.1) # ensure that the full range is covered
day_steps = int(3600 * 24 / (rrdstep * rows))
week_steps = day_steps * 7
month_steps = week_steps * 5
year_steps = month_steps * 12
# Set up data sources for our RRD
params = []
for v in variables:
params += ["DS:%s:%s:%s:0:U" % (v, ds_type, rrdstep * 2)]
# Set up RRD to archive data
for cf in ["AVERAGE", "MAX"]:
for step in [day_steps, week_steps, month_steps, year_steps]:
params += ["RRA:%s:0.5:%s:%s" % (cf, step, realrows)]
# With those setup, we can now created the RRD
rrdtool.create(str(fname),
"--start", str(m),
"--step", str(rrdstep),
*params)
return m
def add_datasource_to_rrd(self, fname, dsname):
"""Add a new data source to an exisitng file.
Add missing Data Sources (DS) to existing Round Robin Archive (RRA):
See init_rrd for details.
"""
ds_def = "DS:%s:ABSOLUTE:%s:0:U" % (dsname, rrdstep * 2)
rrdtool.tune(fname, ds_def)
self._dprint("[rrd] added DS %s to %s" % (dsname, fname))
def add_point_to_rrd(self, fname, tpl, values, ts=None):
"""Try to add a new point to RRD file."""
if ts:
values = "{}:{}".format(ts, values)
if self.verbose:
print("[rrd] VERBOSE update -t %s %s" % (tpl, values))
try:
rrdtool.update(str(fname), "-t", tpl, values)
except rrdtool.OperationalError as e:
op_match = re.match(r"unknown DS name '(\w+)'", str(e))
if op_match is None:
raise
self.add_datasource_to_rrd(str(fname), op_match.group(1))
rrdtool.update(str(fname), "-t", tpl, values)
def update_rrd(self, dom, t):
"""update_rrd
Update RRD with records at t time.
True : if data are up-to-date for current minute
False : syslog may have probably been already recorded
or something wrong
"""
fname = "%s/%s.rrd" % (self.workdir, dom)
m = t - (t % rrdstep)
self._dprint("[rrd] updating %s" % fname)
if not os.path.exists(fname):
self.lupdates[fname] = self.init_rrd(fname, m)
self._dprint("[rrd] create new RRD file %s" % fname)
else:
if fname not in self.lupdates:
self.lupdates[fname] = rrdtool.last(str(fname))
if m <= self.lupdates[fname]:
if self.verbose:
print("[rrd] VERBOSE events at %s already recorded in RRD" % m)
return False
tpl = ""
for v in variables:
if tpl != "":
tpl += ":"
tpl += v
# Missing some RRD steps
# Est ce vraiment nécessaire... ?
if m > self.lupdates[fname] + rrdstep:
values = ""
for v in variables:
if values != "":
values += ":"
values += "0"
for p in range(self.lupdates[fname] + rrdstep, m, rrdstep):
self.add_point_to_rrd(fname, tpl, values, ts=p)
values = "%s" % m
tpl = ""
for v in variables:
values += ":"
values += str(self.data[dom][m][v])
if tpl != "":
tpl += ":"
tpl += v
self.add_point_to_rrd(fname, tpl, values)
self.lupdates[fname] = m
return True
def initcounters(self, dom):
init = {}
for v in variables:
init[v] = 0
self.data[dom][self.cur_t] = init
def inc_counter(self, dom, counter, val=1):
if dom is not None and dom in self.domains:
if self.cur_t not in self.data[dom]:
self.initcounters(dom)
self.data[dom][self.cur_t][counter] += val
if self.cur_t not in self.data["global"]:
self.initcounters("global")
self.data["global"][self.cur_t][counter] += val
def year(self, month):
"""Return the appropriate year
Date used in log files don't always embark the year so we need
to guess it :p
This method tries to deal with year changes in a simply
(ugly?) way: if we currently are in january and the given
month is different, return the current year -1. Otherwise,
return the current year.
Obviously, this method only works for year to year + 1
changes.
:param month: the month of the current record beeing parsed
:return: an integer
"""
month = time.strptime(month, "%b").tm_mon if not month.isdigit() \
else int(month)
if self.curmonth == 1 and month != self.curmonth:
return self.__year - 1
return self.__year
def is_srs_forward(self, mail_address):
""" Check if mail address has been mangled by SRS
Sender Rewriting Scheme (SRS) modifies mail adresses so that they
always end in a local domain.
:param str mail_address
:return a boolean
"""
return self._srs_regex["detect_srs"].match(mail_address) is not None
def reverse_srs(self, mail_address):
""" Try to unwind a mail address rewritten by SRS
Sender Rewriting Scheme (SRS) modifies mail adresses so that they
always end in a local domain. Common Postfix implementations of SRS
rewrite all non-local mail addresss.
:param str mail_address
:return a str
"""
m = self._srs_regex["reverse_srs0"].match(mail_address)
m = self._srs_regex["reverse_srs1"].match(mail_address) \
if m is None else m
if m is not None:
return "%s@%s" % m.group(2, 1)
else:
return mail_address
def _parse_amavis(self, log, host, pid, subprog):
""" Parse an Amavis log entry.
:param str log: logged message
:param str host: hostname
:param str pid: process ID
:return: True on success
"""
m = self._regex["amavis"].search(log)
if m is not None:
dom = m.group("domain")
spam_result = m.group("result")
if dom is not None and dom in self.domains:
if spam_result == "INFECTED":
self.inc_counter(dom, "virus")
elif spam_result in ["SPAM", "SPAMMY"]:
self.inc_counter(dom, "spam")
return True
return False
def _parse_rmilter(self, log, host, pid, subprog):
""" Parse an Rmilter log entry.
:param str log: logged message
:param str host: hostname
:param str pid: process ID
:return: True on success
"""
m = self._regex["rmilter_line"].match(log)
if m is None:
return False
rmilter_hash, msg = m.groups()
workdict_key = "rmilter_" + rmilter_hash
# Virus check must come before spam check due to pattern similarity.
m = self._regex["rmilter_virus"].match(msg)
if m is not None:
self.workdict[workdict_key] = {
"action": "virus"
}
return True
m = self._regex["rmilter_spam"].match(msg)
if m is not None:
self.workdict[workdict_key] = {
"action": "spam"
}
return True
# Greylisting
if self.greylist:
m = self._regex["rmilter_greylist"].search(msg)
if m is not None:
self.workdict[workdict_key] = {
"action": "greylist"
}
return True
# Gather information about message sender and queue ID
m = self._regex["rmilter_msg_done"].match(msg)
if m is not None:
dom = split_mailbox(m.group("rcpt"))[1]
if workdict_key in self.workdict:
action = self.workdict[workdict_key].get("action", None)
if action is not None:
self.inc_counter(dom, action)
return True
return False
def _parse_postfix(self, log, host, pid, subprog):
""" Parse a log entry generated by Postfix.
:param str log: logged message
:param str host: hostname
:param str pid: process ID
:return: True on success
"""
m = self._regex["id"].match(log)
if m is None:
return False
queue_id, msg = m.groups()
# Handle rejected mails.
if queue_id == "NOQUEUE":
m = self._regex["reject"].match(msg)
dom = m.group(1) if m is not None else None
if dom in self.domains:
condition = (
self.greylist and (
"Greylisted" in msg or
(subprog == "postscreen" and " 450 " in msg))
)
if condition:
self.inc_counter(dom, "greylist")
else:
self.inc_counter(dom, "reject")
return True
# Message acknowledged.
m = self._regex["message-id"].search(msg)
if m is not None:
self.workdict[queue_id] = {"from": m.group(1), "size": 0}
return True
# Message enqueued.
m = self._regex["from+size"].search(msg)
if m is not None:
self.workdict[queue_id] = {
"from": self.reverse_srs(m.group(1)),
"size": int(m.group(2))
}
return True
# Message disposition.
m = self._regex["to+status"].search(msg)
if m is None:
return False
(msg_to, msg_status) = m.groups()
if queue_id not in self.workdict:
self._dprint("[parser] inconsistent mail (%s: %s), skipping"
% (queue_id, msg_to))
return True
if msg_status not in variables:
self._dprint("[parser] unsupported status %s, skipping"
% msg_status)
return True
# orig_to is optional.
m = self._regex["orig_to"].search(msg)
msg_orig_to = m.group(1) if m is not None else None
# Handle local "from" domains.
from_domain = split_mailbox(self.workdict[queue_id]["from"])[1]
if from_domain is not None and from_domain in self.domains:
self.inc_counter(from_domain, "sent")
self.inc_counter(from_domain, "size_sent",
self.workdict[queue_id]["size"])
# Handle local "to" domains.
to_domain = None
condition = (
msg_orig_to is not None and
not self.is_srs_forward(msg_orig_to)
)
if condition:
to_domain = split_mailbox(msg_orig_to)[1]
if to_domain is None:
to_domain = split_mailbox(msg_to)[1]
if msg_status == "sent":
self.inc_counter(to_domain, "recv")
self.inc_counter(to_domain, "size_recv",
self.workdict[queue_id]["size"])
else:
self.inc_counter(to_domain, msg_status)
last_message = models.Maillog.objects.last()
cur_dt = datetime.fromtimestamp(self.orig_ts)
tz = timezone.get_current_timezone()
cur_dt = tz.localize(cur_dt)
condition = (
last_message and (
cur_dt < last_message.date or
(cur_dt == last_message.date and
models.Maillog.objects.filter(
date=cur_dt, queue_id=queue_id).exists())
)
)
if not condition:
if from_domain in self.domains:
from_domain = Domain.objects.filter(
Q(name=from_domain) |
Q(domainalias__name=from_domain)
).first()
else:
from_domain = None
if to_domain in self.domains:
to_domain = Domain.objects.filter(
Q(name=to_domain) |
Q(domainalias__name=to_domain)
).first()
else:
to_domain = None
if msg_status == "sent" and to_domain:
msg_status = "received"
models.Maillog.objects.create(
queue_id=queue_id,
date=cur_dt,
sender=self.workdict[queue_id]["from"],
rcpt=msg_to,
original_rcpt=msg_orig_to,
size=self.workdict[queue_id]["size"],
status=msg_status,
from_domain=from_domain,
to_domain=to_domain
)
return True
def _parse_line(self, line):
"""Parse a single log line.
:param str line: log line
"""
line = self._parse_date(line)
if line is None:
return
m = self._regex["line"].match(line)
if not m:
return
host, prog, subprog, pid, log = m.groups()
try:
parser = getattr(self, "_parse_{}".format(prog))
if not parser(log, host, pid, subprog):
self._dprint("[parser] ignoring %r log: %r" % (prog, log))
except AttributeError:
self._dprint(
"[parser] no log handler for \"{}\": {}".format(prog, log))
def process(self):
"""Process the log file.
We parse it and then generate standard graphics (day, week,
month).
"""
for line in self.f.readlines():
self._parse_line(line)
for dom, data in self.data.items():
self._dprint("[rrd] dealing with domain %s" % dom)
for t in sorted(data.keys()):
self.update_rrd(dom, t)
class Command(BaseCommand):
help = "Log file parser"
def add_arguments(self, parser):
"""Add extra arguments to command line."""
parser.add_argument(
"--logfile", default=None,
help="postfix log in syslog format", metavar="FILE")
parser.add_argument(
"--verbose", default=False, action="store_true",
dest="verbose", help="Set verbose mode")
parser.add_argument(
"--debug", default=False, action="store_true",
help="Set debug mode")
def handle(self, *args, **options):
if options["logfile"] is None:
options["logfile"] = param_tools.get_global_parameter(
"logfile", app="maillog")
greylist = param_tools.get_global_parameter(
"greylist", raise_exception=False)
p = LogParser(
options, param_tools.get_global_parameter("rrd_rootdir"),
None, greylist
)
p.process()
@@ -0,0 +1,84 @@
"""Management command to update various statistics."""
import os
from dateutil.relativedelta import relativedelta
import rrdtool
from django.core.management.base import BaseCommand
from django.utils import timezone
from modoboa.core import models as core_models
from modoboa.parameters import tools as param_tools
class Command(BaseCommand):
"""Update statistics."""
help = "Update modoboa statistics"
def add_arguments(self, parser):
"""Add extra arguments to command line."""
parser.add_argument(
"--rebuild", action="store_true",
help="Rebuild statistics from the begining")
def _create_new_accounts_rrd_file(self, fname, start):
"""Create RRD file."""
step = 3600
ds_name = "new_accounts"
params = ["DS:{}:ABSOLUTE:{}:0:U".format(ds_name, step * 2)]
params += [
"RRA:AVERAGE:0.5:1:48", # 48 hours with a 1h granularity
"RRA:AVERAGE:0.5:24:31", # 31 days with a 1d granularity
"RRA:AVERAGE:0.5:168:52", # 52 weeks with a 1w granularity
"RRA:AVERAGE:0.5:5208:24", # 24 months with a 1m granularity
]
rrdtool.create(
str(fname), "--start", str(start), "--step", str(step),
*params
)
def update_account_creation_stats(self, rebuild=False):
"""Look for newly created accounts."""
db_path = os.path.join(self.rootdir, "new_accounts.rrd")
data = []
if not rebuild:
end = timezone.now().replace(minute=0, second=0, microsecond=0)
start = end - relativedelta(hours=1)
new_accounts = core_models.User.objects.filter(
date_joined__gte=start, date_joined__lt=end).count()
data.append(
"{}:{}".format(int(end.strftime("%s")), new_accounts * 60))
else:
existing_stats = {}
start = None
for user in core_models.User.objects.all().order_by("date_joined"):
hour = user.date_joined.replace(
minute=0, second=0, microsecond=0) + relativedelta(hours=1)
if start is None:
start = hour
hour = int(hour.strftime("%s"))
if hour not in existing_stats:
existing_stats[hour] = 0
existing_stats[hour] += 1
end = timezone.now().replace(
minute=0, second=0, microsecond=0) + relativedelta(hours=1)
if os.path.exists(db_path):
os.unlink(db_path)
hour = start
while hour <= end:
new_accounts = existing_stats.get(int(hour.strftime("%s")), 0)
data.append("{}:{}".format(
int(hour.strftime("%s")), new_accounts * 60))
hour += relativedelta(hours=1)
if not os.path.exists(db_path):
self._create_new_accounts_rrd_file(
db_path, int((start - relativedelta(hours=1)).strftime("%s"))
)
rrdtool.update(str(db_path), *data)
def handle(self, *args, **options):
"""Entry point."""
self.rootdir = param_tools.get_global_parameter("rrd_rootdir")
self.update_account_creation_stats(options["rebuild"])
@@ -0,0 +1,34 @@
# Generated by Django 2.2.12 on 2020-09-16 09:13
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('admin', '0017_alarm'),
]
operations = [
migrations.CreateModel(
name='Maillog',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('queue_id', models.CharField(max_length=50)),
('date', models.DateTimeField()),
('sender', models.EmailField(max_length=254)),
('rcpt', models.EmailField(max_length=254)),
('original_rcpt', models.EmailField(max_length=254, null=True)),
('size', models.PositiveIntegerField()),
('status', models.CharField(max_length=15)),
('from_domain', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sent_messages_log', to='admin.Domain')),
('to_domain', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='recv_messages_log', to='admin.Domain')),
],
options={
'ordering': ['date'],
},
),
]
@@ -0,0 +1,36 @@
# Generated by Django 2.2.12 on 2020-09-16 11:46
from django.db import migrations
def rename_settings(apps, schema_editor):
LocalConfig = apps.get_model("core", "LocalConfig")
lc = LocalConfig.objects.first()
if not lc:
return
stats_params = lc._parameters.pop("modoboa_stats", None)
if stats_params:
lc._parameters["maillog"] = stats_params
lc.save()
def backwards(apps, schema_editor):
LocalConfig = apps.get_model("core", "LocalConfig")
lc = LocalConfig.objects.first()
if not lc:
return
params = lc._parameters.pop("maillog", None)
if params:
lc._parameters["modoboa_stats"] = params
lc.save()
class Migration(migrations.Migration):
dependencies = [
('maillog', '0001_initial'),
]
operations = [
migrations.RunPython(rename_settings, backwards),
]
+27
View File
@@ -0,0 +1,27 @@
"""App. related models."""
from django.db import models
class Maillog(models.Model):
"""A model to store message logs."""
queue_id = models.CharField(max_length=50)
date = models.DateTimeField()
sender = models.EmailField()
rcpt = models.EmailField()
original_rcpt = models.EmailField(null=True)
size = models.PositiveIntegerField()
status = models.CharField(max_length=15)
from_domain = models.ForeignKey(
"admin.Domain", on_delete=models.SET_NULL, null=True,
related_name="sent_messages_log"
)
to_domain = models.ForeignKey(
"admin.Domain", on_delete=models.SET_NULL, null=True,
related_name="recv_messages_log"
)
class Meta:
ordering = ['date']
+301
View File
@@ -0,0 +1,301 @@
"""Parsing tools for maillog related files."""
import io
import re
import time
from modoboa.admin import models as admin_models
from modoboa.lib.email_utils import split_mailbox
from . import utils
class MaillogParser:
"""Main parser class for maillog file."""
def __init__(self, year=None, greylist=False, verbose=False, debug=False):
"""Constructor."""
self.debug = debug
self.verbose = verbose
self.domains = []
self._load_domain_list()
self.workdict = {}
self.lupdates = {}
self.__year = year
curtime = time.localtime()
if not self.__year:
self.__year = curtime.tm_year
self.curmonth = curtime.tm_mon
# set up regular expression
self._date_expressions = [
r"(?P<month>\w+)\s+(?P<day>\d+)\s+(?P<hour>\d+):(?P<min>\d+):(?P<sec>\d+)(?P<eol>.*)", # noqa
r"(?P<year>\d+)-(?P<month>\d+)-(?P<day>\d+)T(?P<hour>\d+):(?P<min>\d+):(?P<sec>\d+)\.\d+\+\d+:\d+(?P<eol>.*)" # noqa
]
self._date_expressions = [
re.compile(v) for v in self._date_expressions]
self.date_expr = None
self._regex = {
"line": r"\s+([-\w\.]+)\s+(\w+)/?(\w*)[[](\d+)[]]:\s+(.*)",
"id": r"(\w+): (.*)",
"reject": r"reject: .*from=<.*>,? to=<[^@]+@([^>]+)>",
"message-id": r"message-id=<([^>]*)>",
"from+size": r"from=<([^>]*)>, size=(\d+)",
"to+status": r"to=<([^>]*)>.*status=(\S+)",
"orig_to": r"orig_to=<([^>]*)>.*",
}
self._regex = {k: re.compile(v) for k, v in self._regex.items()}
self._srs_regex = {
"detect_srs": "^SRS[01][+-=]",
"reverse_srs0": r"^SRS0[+-=]\S+=\S{2}=(\S+)=(\S+)\@\S+$",
"reverse_srs1": r"^SRS1[+-=]\S+=\S+==\S+=\S{2}=(\S+)=(\S+)\@\S+$"
}
self._srs_regex = {
k: re.compile(v, re.IGNORECASE) for k, v in self._srs_regex.items()
}
self.greylist = greylist
if greylist:
self._dprint("[settings] greylisting enabled")
def _load_domain_list(self):
"""Load the list of allowed domains."""
for dom in admin_models.Domain.objects.all():
domname = str(dom.name)
self.domains += [domname]
# Also add alias domains
for alias in dom.domainalias_set.all():
aliasname = str(alias.name)
self.domains += [aliasname]
def _dprint(self, msg):
"""Print a debug message if required.
:param str msg: debug message
"""
if not self.debug:
return
print(msg)
def year(self, month):
"""Return the appropriate year
Date used in log files don't always embark the year so we need
to guess it :p
This method tries to deal with year changes in a simply
(ugly?) way: if we currently are in january and the given
month is different, return the current year -1. Otherwise,
return the current year.
Obviously, this method only works for year to year + 1
changes.
:param month: the month of the current record beeing parsed
:return: an integer
"""
month = (
time.strptime(month, "%b").tm_mon if not month.isdigit()
else int(month)
)
if self.curmonth == 1 and month != self.curmonth:
return self.__year - 1
return self.__year
def _store_current_date(self, match):
"""Transform and store parsed date."""
ho = match.group("hour")
mi = match.group("min")
se = match.group("sec")
mo = match.group("month")
da = match.group("day")
try:
ye = match.group("year")
except IndexError:
ye = self.year(mo)
self.cur_t = utils.date_to_timestamp([ye, mo, da, ho, mi, se])
def _parse_date(self, line):
"""Try to match a date inside :kw:`line` and to convert it to
a timestamp.
We try different date format until we find valid one. We then
store it for future use.
:param str line: a log entry
:return: the remaining part of the line or None
"""
match = None
if self.date_expr is None:
for expr in self._date_expressions:
match = expr.match(line)
if match is not None:
self.date_expr = expr
break
else:
match = self.date_expr.match(line)
if match is None:
return None
self._store_current_date(match)
return match.group("eol")
def is_srs_forward(self, mail_address):
""" Check if mail address has been mangled by SRS
Sender Rewriting Scheme (SRS) modifies mail adresses so that they
always end in a local domain.
:param str mail_address
:return a boolean
"""
return self._srs_regex["detect_srs"].match(mail_address) is not None
def reverse_srs(self, mail_address):
""" Try to unwind a mail address rewritten by SRS
Sender Rewriting Scheme (SRS) modifies mail adresses so that they
always end in a local domain. Common Postfix implementations of SRS
rewrite all non-local mail addresss.
:param str mail_address
:return a str
"""
m = self._srs_regex["reverse_srs0"].match(mail_address)
m = self._srs_regex["reverse_srs1"].match(mail_address) \
if m is None else m
if m is not None:
return "%s@%s" % m.group(2, 1)
return mail_address
def new_domain_event(self, domain, name, size=None):
"""Take action about new event for domain."""
pass
def new_message_processed(
self, queue_id, msg_status, from_domain, to_domain, msg_to,
msg_orig_to):
"""Store new message in local database."""
pass
def _parse_postfix(self, log, host, pid, subprog):
""" Parse a log entry generated by Postfix.
:param str log: logged message
:param str host: hostname
:param str pid: process ID
:return: True on success
"""
m = self._regex["id"].match(log)
if m is None:
return False
queue_id, msg = m.groups()
# Handle rejected mails.
if queue_id == "NOQUEUE":
m = self._regex["reject"].match(msg)
dom = m.group(1) if m is not None else None
if dom in self.domains:
condition = (
self.greylist and (
"Greylisted" in msg or
(subprog == "postscreen" and " 450 " in msg))
)
self.new_domain_event(
dom, "greylist" if condition else "reject")
return True
# Message acknowledged.
m = self._regex["message-id"].search(msg)
if m is not None:
self.workdict[queue_id] = {"from": m.group(1), "size": 0}
return True
# Message enqueued.
m = self._regex["from+size"].search(msg)
if m is not None:
self.workdict[queue_id] = {
"from": self.reverse_srs(m.group(1)),
"size": int(m.group(2))
}
return True
# Message disposition.
m = self._regex["to+status"].search(msg)
if m is None:
return False
(msg_to, msg_status) = m.groups()
if queue_id not in self.workdict:
self._dprint("[parser] inconsistent mail (%s: %s), skipping"
% (queue_id, msg_to))
return True
# orig_to is optional.
m = self._regex["orig_to"].search(msg)
msg_orig_to = m.group(1) if m is not None else None
# Handle local "from" domains.
from_domain = split_mailbox(self.workdict[queue_id]["from"])[1]
if from_domain is not None and from_domain in self.domains:
self.new_domain_event(
from_domain, "sent", self.workdict[queue_id]["size"])
# Handle local "to" domains.
to_domain = None
condition = (
msg_orig_to is not None and
not self.is_srs_forward(msg_orig_to)
)
if condition:
to_domain = split_mailbox(msg_orig_to)[1]
if to_domain is None:
to_domain = split_mailbox(msg_to)[1]
if msg_status == "sent":
msg_status = "recv"
self.new_domain_event(
to_domain, "recv", self.workdict[queue_id]["size"])
# Store log entry
self.new_message_processed(
queue_id, msg_status, from_domain, to_domain, msg_to, msg_orig_to)
return True
def _parse_line(self, line):
"""Parse a single log line.
:param str line: log line
"""
line = self._parse_date(line)
if line is None:
return
m = self._regex["line"].match(line)
if not m:
return
host, prog, subprog, pid, log = m.groups()
try:
parser = getattr(self, "_parse_{}".format(prog))
if not parser(log, host, pid, subprog):
self._dprint("[parser] ignoring %r log: %r" % (prog, log))
except AttributeError:
self._dprint(
"[parser] no log handler for \"%r\": %r".format(prog, log))
def parse(self, logfile):
"""Process the log file."""
try:
fp = io.open(logfile, encoding="utf-8")
except IOError as errno:
self._dprint("%s" % errno)
return
for line in fp.readlines():
self._parse_line(line)
fp.close()
+5
View File
@@ -0,0 +1,5 @@
"""Modoboa stats signals."""
import django.dispatch
get_graph_sets = django.dispatch.Signal(providing_args=["user"])
@@ -0,0 +1,71 @@
#menubar {
padding-left: 15px;
}
.chart {
position: relative;
margin-bottom: 20px;
}
.grid .tick {
stroke: darkgrey;
stroke-dasharray: 1, 2;
opacity: 0.9;
}
.grid path {
stroke-width: 0;
}
.line_over {
stroke: darkgrey;
stroke-width: 1.5px;
stroke-dasharray: 1, 2;
display: none;
}
.axis {
font-size: 0.7em;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.area, .area2 {
fill-opacity: .6;
}
.brush .extent {
stroke: #fff;
fill-opacity: .125;
shape-rendering: crispEdges;
}
.legend rect {
fill: none;
stroke: black;
opacity: 0;
}
.tip {
position: absolute;
z-index: 20;
top: 60px;
display: none;
font-size: 0.9em;
padding: 5px;
background: rgba(0, 0, 0, 0.6);
color: #fff;
border-radius: 5px;
}
.tip p {
margin: 0;
}
.tracker {
display: none;
}
@@ -0,0 +1,70 @@
// d3.legend.js
// (C) 2012 ziggy.jonsson.nyc@gmail.com
// MIT licence
(function() {
d3.legend = function(g, clicked) {
g.each(function() {
var g = d3.select(this),
items = {},
svg = d3.select(g.property("nearestViewportElement")),
legendPadding = g.attr("data-style-padding") || 5,
lb = g.selectAll(".legend-box").data([true]),
li = g.selectAll(".legend-items").data([true]);
lb.enter().append("rect").classed("legend-box", true);
li.enter().append("g").classed("legend-items", true);
svg.selectAll("[data-legend]").each(function() {
var self = d3.select(this);
items[self.attr("data-legend")] = {
pos: self.attr("data-legend-pos") || this.getBBox().y,
color: self.attr("data-legend-color") != undefined ? self.attr("data-legend-color") : self.style("fill") != 'none' ? self.style("fill") : self.style("stroke")
};
});
items = d3.entries(items).sort(function(a, b) {
return a.value.pos - b.value.pos;
});
li.selectAll("text")
.data(items, function(d) { return d.key; })
.call(function(d) { d.enter().append("text"); })
.call(function(d) { d.exit().remove(); })
.attr("y", function(d, i) { return i + "em"; })
.attr("x", "1em")
.text(function(d) { return d.key; });
li.selectAll("circle")
.data(items, function(d) { return d.key; })
.call(function(d) { d.enter().append("circle"); })
.call(function(d) { d.exit().remove(); })
.attr("cy", function(d, i) { return i - 0.25 + "em"; })
.attr("cx", 0)
.attr("r", "4px")
.style("stroke", function(d) { return d.value.color; })
.style("stroke-width", "1px")
.style("stroke-opacity", 0.8)
.style("fill", function(d) { return d.value.color; })
.on("click", function(d) {
var curve = d3.selectAll("[data-legend='" + d.key + "']");
var state = (curve.style("display") == "none")
? "block" : "none";
curve.style("display", state);
d3.select(this).style(
"fill", (state == "none") ? "none" : d.value.color
);
});
// Reposition and resize the box
var lbbox = li[0][0].getBBox();
lb.attr("x", (lbbox.x - legendPadding))
.attr("y", (lbbox.y - legendPadding))
.attr("height", (lbbox.height + 2 * legendPadding))
.attr("width", (lbbox.width + 2 * legendPadding));
});
return g;
};
})();
@@ -0,0 +1,355 @@
/**
* Creates an instance of ModoChart.
*
* @constructor
* @this {ModoChart}
* @param {string} selection add chart to this DOM element.
*
*/
function ModoChart(selection) {
var width = 0,
height = 300,
preview_height = 80,
brush_height = 7,
margin = {
left: 50,
top: 10,
bottom: 20
};
var container;
/**
* Create and render the chart.
*
* @this {ModoChart}
* @param {Object} data chart's data.
*/
function my(data) {
container = d3.select(selection)
.append("div")
.attr("class", "chart");
container.append("h6").html(data.title);
width = $(selection).width();
var svg = container
.append("svg")
.attr("width", width)
.attr("height", my.totalHeight());
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width - 2 * margin.left)
.attr("height", height + margin.top + margin.bottom);
var x = d3.time.scale().range([0, width - 2 * margin.left]),
x2 = d3.time.scale().range([0, width - 2 * margin.left]);
var xAxis = d3.svg.axis().scale(x).orient("bottom"),
xAxis2 = d3.svg.axis().scale(x2).orient("bottom");
var y = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([preview_height, 0]);
var yAxis = d3.svg.axis().scale(y).orient("left");
var bisectDate = d3.bisector(function(d) { return d.x * 1000; }).left;
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
x.domain(
d3.extent(data.curves[0].data.map(function(d) { return d.x * 1000; }))
);
y.domain(
[d3.min(data.curves, function(d) { return d3.min(d.data, function(v) { return v.y; }); }),
d3.max(data.curves, function(d) { return d3.max(d.data, function(v) { return v.y; }); })
]
);
x2.domain(x.domain());
y2.domain(y.domain());
var area = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x(d.x * 1000); })
.y0(height)
.y1(function(d) { return y(d.y); });
var area2 = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x2(d.x * 1000); })
.y0(preview_height)
.y1(function(d) { return y2(d.y); });
var focus = svg.append("g")
.attr("class", "focus")
.attr("width", width - 2 * margin.left)
.attr("height", height)
.attr("pointer-events", "all")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin.left + "," + (height + margin.top + margin.bottom + brush_height) + ")");
var curvegroup = focus.append("g")
.attr('clip-path', 'url(#clip)');
var curve = curvegroup.selectAll(".curve")
.data(data.curves)
.enter().append("g")
.attr("class", "curve");
var curve2 = context.selectAll(".curve")
.data(data.curves)
.enter().append("g")
.attr("class", "curve");
/* Vertical line */
var line = focus.append("line")
.attr("class", "line_over")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 0)
.attr("y2", height);
/* Custom rectangle to catch mouse events */
var rect = focus.append("rect")
.attr("fill", "none")
.attr("width", width - 2 * margin.left)
.attr("height", height);
var tooltip = container
.append("div")
.attr("class", "remove")
.attr("class", "tip");
var points = [];
var path = curve.append("path")
.attr("class", "area")
.attr("d", function(d, i) {
var path = this;
points[path] = {};
d.data.forEach(function(d) {
points[path][d.x] = d.y;
});
focus.append("circle")
.attr("class", "tracker tracker-" + i)
.attr("r", 4);
return area(d.data);
})
.attr("data-legend", function(d) { return d.name; })
.attr("stroke", function(d) { return d.color; })
.attr("stroke-width", "2px")
.attr("stroke-opacity", 0.8)
.style("fill", function(d) { return d.color; });
var xrules = make_x_axis();
focus.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(xrules);
focus.append("g")
.attr("class", "grid")
.call(make_y_axis);
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class", "y axis")
.call(yAxis);
rect.on("mouseover", function(d) {
line.style("display", "block");
tooltip.style("display", "block");
data.curves.forEach(function(d, cid) {
var display = d3.selectAll("[data-legend='" + d.name + "']")
.style("display");
if (display == "none") {
return;
}
focus.select(".tracker-" + cid).style("display", "block");
});
}).on("mousemove", function(d) {
var mousex = d3.mouse(this)[0],
mousey = d3.mouse(this)[1];
var date = x.invert(mousex);
var text = "";
line.attr("x1", mousex).attr("x2", mousex);
data.curves.forEach(function(d, cid) {
var display = d3.selectAll("[data-legend='" + d.name + "']")
.style("display");
if (display == "none") {
return;
}
var i = bisectDate(d.data, date.getTime(), 1),
d0 = d.data[i - 1],
d1 = d.data[i],
point = date.getTime() - (d0.x * 1000) > (d1.x * 1000) - date.getTime() ? d1 : d0;
text += "<p>" + d.name + ": " + point.y.toFixed(3) + "</p>";
var tracker_x = x(point.x * 1000),
tracker_y = y(point.y);
focus.selectAll(".tracker-" + cid)
.style("fill", d.color)
.attr("cx", tracker_x)
.attr("cy", tracker_y);
});
if (mousex + tooltip[0][0].clientWidth >= width - 2 * margin.left) {
var left = mousex - (tooltip[0][0].clientWidth - (margin.left - 20));
tooltip.style("left", left + "px");
} else {
tooltip.style("left", (mousex + margin.left + 20) + "px");
}
tooltip.html("<p>" + date + "</p>" + text);
}).on("mouseout", function(d) {
tooltip.style("display", "none");
line.style("display", "none");
focus.selectAll(".tracker").style("display", "none");
});
var legend = focus.append("g")
.attr("class", "legend")
.attr("transform", "translate(50,10)")
.style("font-size", "0.8em")
.call(d3.legend);
curve2.append("path")
.attr("class", "area2")
.attr("d", function(d) { return area2(d.data); })
.attr("stroke", function(d) { return d.color; })
.attr("stroke-width", "2px")
.attr("stroke-opacity", 0.8)
.attr("data-legend", function(d) { return d.name; })
.style("fill", function(d) { return d.color; });
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + preview_height + ")")
.call(xAxis2);
context.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + preview_height + ")")
.call(make_preview_x_axis);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", preview_height + brush_height);
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(6)
.tickSize(-height, 0, 0)
.tickFormat("");
}
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(6)
.tickSize(-(width - 2 * margin.left), 0, 0)
.tickFormat("");
}
function make_preview_x_axis() {
return d3.svg.axis()
.scale(x2)
.orient("bottom")
.ticks(6)
.tickSize(-preview_height, 0, 0)
.tickFormat("");
}
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.selectAll(".area")
.attr("d", function(d) { return area(d.data); });
focus.select(".x.axis").call(xAxis);
focus.select(".grid").call(xrules);
}
}
/**
* Set or get chart's width.
*
* @this {ModoChart}
* @param {integer} value new width.
* @return {number} current width.
*/
my.width = function(value) {
if (!arguments.length) return width;
width = value;
return my;
};
/**
* Set or get chart's height.
*
* @this {ModoChart}
* @param {integer} value new height.
* @return {number} current height.
*/
my.height = function(value) {
if (!arguments.length) return height;
height = value;
return my;
};
/**
* Set or get chart's margin.
*
* @this {ModoChart}
* @param {Object} value new margin.
* @return {Object} current margin.
*/
my.margin = function(value) {
if (!arguments.length) return margin;
margin = value;
return my;
};
/**
* Compute and return chart's total height.
*
* @this {ModoChart}
* @return {integer} total height.
*/
my.totalHeight = function() {
return height + 2 * margin.top
+ 2 * margin.bottom + preview_height
+ brush_height;
};
/**
* Update the chart with new data.
*
* @this {ModoChart}
* @param {Object} data new data
*/
my.update = function(data) {
container.select("svg").remove();
$(container[0][0]).empty();
my(data);
};
/**
* Hide the chart.
*
* @this {ModoChart}
*/
my.hide = function () {
container.select("svg").remove();
$(container[0][0]).empty();
};
return my;
}
+189
View File
@@ -0,0 +1,189 @@
/**
* Create an instance of Stats.
*
* @constructor
*/
var Stats = function(options) {
this.initialize(options);
};
Stats.prototype = {
constructor: Stats,
defaults: {
deflocation: "graphs/",
language: "en",
domain_list_url: null
},
initialize: function(options) {
this.options = $.extend({}, this.defaults, options);
this.options.defcallback = $.proxy(this.charts_cb, this);
var navobj = new History(this.options);
this.navobj = navobj;
this.charts = {};
if (navobj.params.searchquery !== undefined) {
$("#searchquery").val(navobj.params.searchquery);
}
$("#searchquery").focus(function() {
var $this = $(this);
if ($this.val() === undefined) {
return;
}
$this.data("oldvalue", $this.val());
$this.val("");
}).blur(function() {
var $this = $(this);
if ($this.val() === "") {
if ($this.data("oldvalue")) {
$this.val($this.data('oldvalue'));
$this.data("oldvalue", null);
} else {
$this.val(gettext("Search a domain"));
}
}
});
if (navobj.params.start) {
$("#id_from").val(navobj.params.start);
}
if (navobj.params.end) {
$("#id_to").val(navobj.params.end);
}
if (navobj.params.period) {
$("input[data-period={0}]".format(navobj.params.period))
.attr("checked", true)
.parent().addClass("active");
if (navobj.params.period == "custom") {
$("#custom_period").removeClass("hidden");
}
}
$("#custom-period .datetime_picker").datetimepicker({
format: 'YYYY-MM-DD HH:mm:ss',
locale: this.options.language,
ignoreReadonly: true
});
$("#searchquery").autocompleter({
choices: $.proxy(this.get_domain_list, this),
choice_selected: $.proxy(this.search_domain, this),
empty_choice: $.proxy(this.reset_search, this)
});
this.register_nav_callbacks();
this.listen();
},
listen: function() {
$(".period_selector").click($.proxy(this.change_period, this));
$("#customsend").on("click", $.proxy(this.custom_period, this));
$(window).resize($.proxy(this.resize_charts, this));
},
register_nav_callbacks: function() {
this.navobj.register_callback("graphs",
$.proxy(this.charts_cb, this));
},
/**
* Retrieve a list of domain from the server.
*/
get_domain_list: function() {
var result;
$.ajax({
url: this.options.domain_list_url,
dataType: "json",
async: false
}).done(function(data) {
result = data;
});
return result;
},
change_period: function(e) {
e.preventDefault();
var $link = $(e.target).children("input");
var period = $link.attr("data-period");
if (period != "custom") {
$("#custom_period").addClass("hidden");
this.navobj.delparam("start").delparam("end");
this.navobj.setparam("period", $link.attr("data-period")).update();
} else {
$("#custom_period").removeClass("hidden");
}
},
/**
* Update all charts on resize event.
*
* @this {Stats}
*/
resize_charts: function() {
var data = this.data;
$.each(this.charts, function(id, mychart) {
mychart.update(data.graphs[id]);
});
},
/**
* Create or update charts.
*
* @this {Stats}
* @param {Object} data
*/
charts_cb: function(data) {
var menuid = "menu_" + this.navobj.getparam("gset");
var activeCharts = new Array();
$(".nav-sidebar > li").removeClass("active");
$("#" + menuid).addClass("active");
this.data = data;
if (!this.data.domain_selector) {
$("#domain-selector").hide();
} else {
$("#domain-selector").show();
}
$.each(data.graphs, $.proxy(function(id, graphdef) {
if (this.charts.hasOwnProperty(id)) {
this.charts[id].update(graphdef);
} else if (graphdef.curves.length) {
var mychart = ModoChart("#gset");
this.charts[id] = mychart;
mychart(graphdef);
}
activeCharts.push(id);
}, this));
$.each(this.charts, function (id, mychart) {
if (activeCharts.indexOf(id) === -1) {
mychart.hide();
}
});
},
search_domain: function(value) {
this.navobj.setparam("searchquery", value).update();
},
reset_search: function() {
$("#searchquery").data("oldvalue", null);
this.navobj.delparam("searchquery").update();
},
custom_period: function(e) {
e.preventDefault();
var $fromdate = $("#id_from");
var $todate = $("#id_to");
if ($fromdate.val() === "" || $todate.val() === "") {
return;
}
this.navobj.setparams({
period: "custom",
start: $fromdate.val(),
end: $todate.val()
}).update();
}
};
@@ -0,0 +1,91 @@
{% extends "twocols.html" %}
{% load i18n static %}
{% block pagetitle %}{% trans "Graphical statistics" %}{% endblock %}
{% block extra_css %}
<link rel="stylesheet" type="text/css" href="{% static 'maillog/css/stats.css' %}" />
{% endblock %}
{% block extra_js %}
<script type="text/javascript" src="{% static 'js/history.js' %}"></script>
<script type="text/javascript" src="{% static 'js/autocompleter.js' %}"></script>
<script type="text/javascript" src="{% static 'd3/d3.min.js' %}"></script>
<script type="text/javascript" src="{% static 'maillog/js/d3.legend.js' %}"></script>
<script type="text/javascript" src="{% static 'maillog/js/graphic.js' %}"></script>
<script type="text/javascript" src="{% static 'maillog/js/stats.js' %}"></script>
<script type="text/javascript">
$(document).ready(function() {
var stats = new Stats({
graphurl: "{% url 'maillog:graph_list' %}",
domain_list_url: "{% url 'maillog:domain_list' %}",
deflocation: "{{ deflocation|safe }}",
language: "{{ LANGUAGE_CODE }}"
});
});
</script>
{% endblock %}
{% block leftcol %}
<ul class="nav nav-sidebar">
{% for id, gset in graph_sets.items %}
<li id="menu_{{ gset.html_id }}">
<a href="#graphs?gset={{ gset.html_id }}">{{ gset.title }}</a>
</li>
{% endfor %}
</ul>
{% endblock %}
{% block apparea %}
<div id="menubar" class="row">
<div id="domain-selector" class="col-sm-5">
<form class="form-horizontal" role="form">
<div class="form-group has-feedback">
<input class="form-control" id="searchquery" type="text" value="{% trans 'Search a domain' %}">
<span class="fa fa-search form-control-feedback"></span>
</div>
</form>
</div>
<div class="col-sm-7">
<div class="btn-group" data-toggle="buttons">
{% for p in periods %}
<label class="btn btn-primary period_selector">
<input type="radio" data-period="{{ p.name }}"> {% trans p.label %}
</label>
{% endfor %}
</div>
</div>
</div>
<div id="custom_period" class="row hidden">
<div class="col-sm-7">
<form class="form-inline">
<span id="custom-period">
<div class="form-group">
<div class="input-group datetime_picker">
<div class="input-group-addon"><span class="fa fa-outdent"></span></div>
<input id="id_from" name="date_form" class="form-control" value="{{ start }}" type="text" readonly="readonly">
</div>
</div>
<div class="form-group">
<div class="input-group datetime_picker">
<div class="input-group-addon"><span class="fa fa-outdent"></span></div>
<input id="id_to" name="date_to" value="{{ end }}" class="form-control" type="text" readonly="readonly" />
</div>
</div>
<button type="submit" class="btn btn-primary" id="customsend">{% trans "Apply" %}</button>
</span>
</form>
</div>
</div>
<div id="graphs">
{% for id, gset in graph_sets.items %}
<div class="tab-pane {% if forloop.first %}active{% endif %}" id="graphs_{{ gset.html_id }}">
<div id="gset"></div>
</div>
{% endfor %}
</div>
{% endblock %}
View File
+519
View File
@@ -0,0 +1,519 @@
%(day)s 11:00:20 server postfix/cleanup[28945]: A0320E00C3: message-id=<cm.2100050552286.huticd.jyidyhxuy.y@cmail19.com>
%(day)s 11:00:20 server postfix/qmgr[26163]: A0320E00C3: from=<visitbrussels-huticd1jyidyhxuy1y@cmail19.com>, size=142646, nrcpt=1 (queue active)
%(day)s 11:00:20 server postfix/smtpd[28944]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:00:20 server amavis[14540]: (14540-09) Passed CLEAN {RelayedInbound}, [103.28.42.139]:56540 [103.28.42.139] <visitbrussels-huticd1jyidyhxuy1y@cmail19.com> -> <user@test.com>, Message-ID: <cm.2100050552286.huticd.jyidyhxuy.y@cmail19.com>, Hits: -1.481, size: 142067, queued_as: A0320E00C3, dkim_sd=cm:mailing.agenda.be, 10172 ms
%(day)s 11:00:20 server postfix/smtpd[28914]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as A0320E00C3; from=<visitbrussels-huticd1jyidyhxuy1y@cmail19.com> to=<user@test.com> proto=ESMTP helo=<mx139.g.outbound.createsend.com>
%(day)s 11:00:20 server dovecot: lmtp(30301): Connect from local
%(day)s 11:00:20 server postfix/smtpd[28914]: disconnect from mx139.g.outbound.createsend.com[103.28.42.139] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5
%(day)s 11:00:20 server dovecot: lmtp(user@test.com): z5FOLrRhDVpddgAABvoInA: sieve: msgid=<cm.2100050552286.huticd.jyidyhxuy.y@cmail19.com>: stored mail into mailbox 'notifications'
%(day)s 11:00:20 server postfix/lmtp[28946]: A0320E00C3: to=<user@test.com>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.32, delays=0.11/0.01/0.01/0.2, dsn=2.0.0, status=sent (250 2.0.0 <user@test.com> z5FOLrRhDVpddgAABvoInA Saved)
%(day)s 11:00:20 server dovecot: lmtp(30301): Disconnect from local: Successful quit
%(day)s 11:00:20 server postfix/qmgr[26163]: A0320E00C3: removed
%(day)s 11:03:05 server postfix/postscreen[30620]: CONNECT from [207.154.235.157]:54810 to [94.23.45.181]:25
%(day)s 11:03:11 server postfix/postscreen[30620]: PASS OLD [207.154.235.157]:54810
%(day)s 11:03:12 server postfix/smtpd[30624]: connect from misas5.babino.pl[207.154.235.157]
%(day)s 11:03:12 server postfix/smtpd[30624]: warning: 157.235.154.207.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=157.235.154.207.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:03:12 server postfix/cleanup[30637]: 2847EE008E: message-id=<20171116100312.2847EE008E@mail.koalabs.org>
%(day)s 11:03:12 server postfix/qmgr[26163]: 2847EE008E: from=<double-bounce@mail.koalabs.org>, size=271, nrcpt=1 (queue active)
%(day)s 11:03:12 server policyd-spf[30640]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=207.154.235.157; helo=misas5.babino.pl; envelope-from=zwroty@babino.pl; receiver=<UNKNOWN>
%(day)s 11:03:12 server postfix/smtpd[30624]: NOQUEUE: client=misas5.babino.pl[207.154.235.157]
%(day)s 11:03:15 server postfix/smtpd[30647]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:03:15 server postfix/smtpd[30647]: 1FEB7E00C4: client=localhost.localdomain[127.0.0.1], orig_client=misas5.babino.pl[207.154.235.157]
%(day)s 11:03:15 server postfix/cleanup[30637]: 1FEB7E00C4: message-id=<de35d4cf3b0862e276fc1afc2f0c14d6@link.crazygecko.pl>
%(day)s 11:03:15 server postfix/qmgr[26163]: 1FEB7E00C4: from=<zwroty@babino.pl>, size=53549, nrcpt=1 (queue active)
%(day)s 11:03:15 server postfix/smtpd[30647]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:03:15 server amavis[19749]: (19749-18) Passed SPAM {RelayedTaggedInbound}, [207.154.235.157]:54810 [207.154.235.157] <zwroty@babino.pl> -> <info@test2.com>, Message-ID: <de35d4cf3b0862e276fc1afc2f0c14d6@link.crazygecko.pl>, Hits: 6.89, size: 52477, queued_as: 1FEB7E00C4, dkim_sd=1509955623.babino:babino.pl, 2365 ms
%(day)s 11:03:15 server postfix/smtpd[30624]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 1FEB7E00C4; from=<zwroty@babino.pl> to=<info@test2.com> proto=ESMTP helo=<misas5.babino.pl>
%(day)s 11:03:15 server postfix/smtpd[30624]: disconnect from misas5.babino.pl[207.154.235.157] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5
%(day)s 11:03:18 server postfix/smtp[30639]: Anonymous TLS connection established to mail.domain.test[94.23.191.34]:25: TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)
%(day)s 11:03:18 server postfix/smtp[30639]: 2847EE008E: to=<info@test2.com>, relay=mail.domain.test[94.23.191.34]:25, delay=6.3, delays=0.04/0.01/6/0.19, dsn=2.1.5, status=deliverable (250 2.1.5 Ok)
%(day)s 11:03:18 server postfix/qmgr[26163]: 2847EE008E: removed
%(day)s 11:03:21 server postfix/smtp[30648]: Anonymous TLS connection established to mail.domain.test[94.23.191.34]:25: TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)
%(day)s 11:03:26 server postfix/smtp[30648]: 1FEB7E00C4: to=<info@test2.com>, relay=mail.domain.test[94.23.191.34]:25, delay=11, delays=0.05/0.01/6.1/5.2, dsn=2.0.0, status=sent (250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 5DDDA1F30002)
%(day)s 11:03:26 server postfix/qmgr[26163]: 1FEB7E00C4: removed
%(day)s 11:04:01 server dovecot: imap-login: Login: user=<anomalie@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=30726, secured, session=<QlNHvRZeMMd/AAAB>
%(day)s 11:04:01 server dovecot: imap(anomalie@test2.com): Logged out in=86 out=892
%(day)s 11:04:01 server dovecot: imap-login: Login: user=<evolution@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=30742, secured, session=<2fBIvRZeMcd/AAAB>
%(day)s 11:04:01 server dovecot: imap(evolution@test2.com): Logged out in=86 out=891
%(day)s 11:04:01 server dovecot: imap-login: Login: user=<question@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=30754, secured, session=<YFdKvRZeMsd/AAAB>
%(day)s 11:04:01 server dovecot: imap(question@test2.com): Logged out in=86 out=891
%(day)s 11:04:15 server dovecot: imap-login: Login: user=<admin@test.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=30828, secured, session=<zUgbvhZeXcd/AAAB>
%(day)s 11:04:18 server dovecot: imap-login: Login: user=<admin@test.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=30866, secured, session=<XKFHvhZeasd/AAAB>
%(day)s 11:04:32 server postfix/postscreen[30620]: CONNECT from [127.0.0.1]:53903 to [127.0.0.1]:25
%(day)s 11:04:32 server postfix/postscreen[30620]: WHITELISTED [127.0.0.1]:53903
%(day)s 11:04:32 server postfix/smtpd[30624]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:04:32 server opendmarc[4245]: ignoring connection from localhost.localdomain
%(day)s 11:04:32 server postfix/smtpd[30624]: NOQUEUE: client=localhost.localdomain[127.0.0.1]
%(day)s 11:04:32 server postfix/smtpd[30647]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:04:32 server postfix/smtpd[30647]: 8D1B3E008E: client=localhost.localdomain[127.0.0.1], orig_client=localhost.localdomain[127.0.0.1]
%(day)s 11:04:32 server postfix/cleanup[30637]: 8D1B3E008E: message-id=<20171116100432.10564.83744@server.ngyn.org>
%(day)s 11:04:32 server postfix/smtpd[30647]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:04:32 server postfix/qmgr[26163]: 8D1B3E008E: from=<root@localhost>, size=18506, nrcpt=1 (queue active)
%(day)s 11:04:32 server amavis[21816]: (21816-19) Passed CLEAN {RelayedInternal}, MYNETS LOCAL [127.0.0.1]:53903 <root@localhost> -> <admin@test.com>, Message-ID: <20171116100432.10564.83744@server.ngyn.org>, Hits: -, size: 18043, queued_as: 8D1B3E008E, 102 ms
%(day)s 11:04:32 server postfix/smtpd[30624]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 8D1B3E008E; from=<root@localhost> to=<admin@test.com> proto=ESMTP helo=<server.ngyn.org>
%(day)s 11:04:32 server postfix/smtpd[30624]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5
%(day)s 11:04:32 server dovecot: lmtp(30933): Connect from local
%(day)s 11:04:32 server postfix/postscreen[30620]: CONNECT from [127.0.0.1]:53914 to [127.0.0.1]:25
%(day)s 11:04:32 server postfix/postscreen[30620]: WHITELISTED [127.0.0.1]:53914
%(day)s 11:04:32 server postfix/smtpd[30624]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:04:32 server opendmarc[4245]: ignoring connection from localhost.localdomain
%(day)s 11:04:32 server postfix/smtpd[30624]: NOQUEUE: client=localhost.localdomain[127.0.0.1]
%(day)s 11:04:32 server postfix/smtpd[30647]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:04:32 server postfix/smtpd[30647]: AA7FDE00C4: client=localhost.localdomain[127.0.0.1], orig_client=localhost.localdomain[127.0.0.1]
%(day)s 11:04:32 server postfix/cleanup[30637]: AA7FDE00C4: message-id=<20171116100432.10564.58862@server.ngyn.org>
%(day)s 11:04:32 server postfix/smtpd[30647]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:04:32 server postfix/qmgr[26163]: AA7FDE00C4: from=<root@localhost>, size=18506, nrcpt=1 (queue active)
%(day)s 11:04:32 server amavis[5246]: (05246-16) Passed CLEAN {RelayedInternal}, MYNETS LOCAL [127.0.0.1]:53914 <root@localhost> -> <admin@test.com>, Message-ID: <20171116100432.10564.58862@server.ngyn.org>, Hits: -, size: 18043, queued_as: AA7FDE00C4, 79 ms
%(day)s 11:04:32 server postfix/smtpd[30624]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as AA7FDE00C4; from=<root@localhost> to=<admin@test.com> proto=ESMTP helo=<server.ngyn.org>
%(day)s 11:04:32 server postfix/smtpd[30624]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5
%(day)s 11:04:32 server dovecot: lmtp(30937): Connect from local
%(day)s 11:04:32 server dovecot: lmtp(admin@test.com): cqWOJrBiDVrVeAAABvoInA: sieve: msgid=<20171116100432.10564.83744@server.ngyn.org>: stored mail into mailbox 'Koalabs'
%(day)s 11:04:32 server dovecot: lmtp(30933): Disconnect from local: Successful quit
%(day)s 11:04:32 server postfix/lmtp[30932]: 8D1B3E008E: to=<admin@test.com>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.26, delays=0.06/0.01/0.01/0.19, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> cqWOJrBiDVrVeAAABvoInA Saved)
%(day)s 11:04:32 server postfix/qmgr[26163]: 8D1B3E008E: removed
%(day)s 11:04:32 server dovecot: lmtp(admin@test.com): ES02LbBiDVrZeAAABvoInA: sieve: msgid=<20171116100432.10564.58862@server.ngyn.org>: stored mail into mailbox 'Koalabs'
%(day)s 11:04:32 server dovecot: lmtp(30937): Disconnect from local: Successful quit
%(day)s 11:04:32 server postfix/lmtp[30936]: AA7FDE00C4: to=<admin@test.com>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.22, delays=0.05/0/0.01/0.16, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> ES02LbBiDVrZeAAABvoInA Saved)
%(day)s 11:04:32 server postfix/qmgr[26163]: AA7FDE00C4: removed
%(day)s 11:06:45 server postfix/postscreen[31171]: CONNECT from [185.5.53.87]:58092 to [94.23.45.181]:25
%(day)s 11:06:45 server postfix/postscreen[31171]: PASS OLD [185.5.53.87]:58092
%(day)s 11:06:45 server postfix/smtpd[31172]: connect from main.nope.org.es[185.5.53.87]
%(day)s 11:06:45 server postfix/smtpd[31172]: Anonymous TLS connection established from main.nope.org.es[185.5.53.87]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
%(day)s 11:06:45 server postfix/smtpd[31172]: warning: 87.53.5.185.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=87.53.5.185.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:06:46 server policyd-spf[31184]: prepend Received-SPF: None (no SPF record) identity=no SPF record; client-ip=185.5.53.87; helo=main.nope.org.es; envelope-from=<>; receiver=<UNKNOWN>
%(day)s 11:06:46 server postfix/smtpd[31172]: NOQUEUE: client=main.nope.org.es[185.5.53.87]
%(day)s 11:06:51 server postfix/smtpd[31201]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:06:51 server postfix/smtpd[31201]: AA3E6E00C3: client=localhost.localdomain[127.0.0.1], orig_client=main.nope.org.es[185.5.53.87]
%(day)s 11:06:51 server postfix/cleanup[31202]: AA3E6E00C3: message-id=<201711161006.vAGA6jpH019527@main.nope.org.es>
%(day)s 11:06:51 server postfix/smtpd[31201]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:06:51 server postfix/qmgr[26163]: AA3E6E00C3: from=<>, size=3194, nrcpt=1 (queue active)
%(day)s 11:06:51 server amavis[14540]: (14540-10) Passed CLEAN {RelayedInbound}, [185.5.53.87]:58092 [185.5.53.87] <> -> <noreply@modoboa.org>, Message-ID: <201711161006.vAGA6jpH019527@main.nope.org.es>, Hits: -1.889, size: 2718, queued_as: AA3E6E00C3, 5178 ms
%(day)s 11:06:51 server postfix/smtpd[31172]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as AA3E6E00C3; from=<> to=<noreply@modoboa.org> proto=ESMTP helo=<main.nope.org.es>
%(day)s 11:06:51 server dovecot: lmtp(31204): Connect from local
%(day)s 11:06:51 server dovecot: lmtp(admin@test.com): wUc3LDtjDVrkeQAABvoInA: sieve: msgid=<201711161006.vAGA6jpH019527@main.nope.org.es>: not sending reject message to <>
%(day)s 11:06:51 server postfix/lmtp[31203]: AA3E6E00C3: to=<admin@test.com>, orig_to=<noreply@modoboa.org>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.07, delays=0.04/0.01/0.01/0.01, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> wUc3LDtjDVrkeQAABvoInA Saved)
%(day)s 11:06:51 server dovecot: lmtp(31204): Disconnect from local: Successful quit
%(day)s 11:06:51 server postfix/qmgr[26163]: AA3E6E00C3: removed
%(day)s 11:06:52 server policyd-spf[31184]: prepend Received-SPF: None (no SPF record) identity=no SPF record; client-ip=185.5.53.87; helo=main.nope.org.es; envelope-from=<>; receiver=<UNKNOWN>
%(day)s 11:06:52 server postfix/smtpd[31172]: NOQUEUE: client=main.nope.org.es[185.5.53.87]
%(day)s 11:06:54 server postfix/smtpd[31201]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:06:54 server postfix/smtpd[31201]: 94D70E00C3: client=localhost.localdomain[127.0.0.1], orig_client=main.nope.org.es[185.5.53.87]
%(day)s 11:06:54 server postfix/cleanup[31202]: 94D70E00C3: message-id=<201711161006.vAGA6jpI019527@main.nope.org.es>
%(day)s 11:06:54 server postfix/smtpd[31201]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:06:54 server postfix/qmgr[26163]: 94D70E00C3: from=<>, size=2988, nrcpt=1 (queue active)
%(day)s 11:06:54 server dovecot: lmtp(31204): Connect from local
%(day)s 11:06:54 server dovecot: lmtp(admin@test.com): AQQ5Jz5jDVrkeQAABvoInA: sieve: msgid=<201711161006.vAGA6jpI019527@main.nope.org.es>: not sending reject message to <>
%(day)s 11:06:54 server postfix/lmtp[31203]: 94D70E00C3: to=<admin@test.com>, orig_to=<noreply@modoboa.org>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.05, delays=0.05/0/0/0, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> AQQ5Jz5jDVrkeQAABvoInA Saved)
%(day)s 11:06:54 server dovecot: lmtp(31204): Disconnect from local: Successful quit
%(day)s 11:06:54 server postfix/qmgr[26163]: 94D70E00C3: removed
%(day)s 11:06:54 server amavis[19749]: (19749-19) Passed CLEAN {RelayedInbound}, [185.5.53.87]:58092 [185.5.53.87] <> -> <noreply@modoboa.org>, Message-ID: <201711161006.vAGA6jpI019527@main.nope.org.es>, Hits: -1.889, size: 2512, queued_as: 94D70E00C3, 2262 ms
%(day)s 11:06:54 server postfix/smtpd[31172]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 94D70E00C3; from=<> to=<noreply@modoboa.org> proto=ESMTP helo=<main.nope.org.es>
%(day)s 11:06:54 server postfix/smtpd[31172]: disconnect from main.nope.org.es[185.5.53.87] ehlo=2 starttls=1 mail=2 rcpt=2 data=2 rset=1 quit=1 commands=11
%(day)s 11:09:09 server postfix/anvil[28916]: statistics: max connection rate 1/60s for (smtpd:192.254.112.99) at %(day)s 10:59:09
%(day)s 11:09:09 server postfix/anvil[28916]: statistics: max connection count 1 for (smtpd:192.254.112.99) at %(day)s 10:59:09
%(day)s 11:09:09 server postfix/anvil[28916]: statistics: max cache size 3 at %(day)s 11:00:08
%(day)s 11:10:02 server dovecot: imap-login: Login: user=<anomalie@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=31600, secured, session=<uVXK0hZeLMh/AAAB>
%(day)s 11:10:02 server dovecot: imap(anomalie@test2.com): Logged out in=86 out=892
%(day)s 11:10:02 server dovecot: imap-login: Login: user=<evolution@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=31618, secured, session=<VhXM0hZeLch/AAAB>
%(day)s 11:10:02 server dovecot: imap(evolution@test2.com): Logged out in=86 out=891
%(day)s 11:10:02 server dovecot: imap-login: Login: user=<question@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=31630, secured, session=<n4HN0hZeLsh/AAAB>
%(day)s 11:10:02 server dovecot: imap(question@test2.com): Logged out in=86 out=891
%(day)s 11:14:42 server postfix/postscreen[32096]: CONNECT from [51.15.3.241]:35169 to [94.23.45.181]:25
%(day)s 11:14:42 server postfix/postscreen[32096]: PASS OLD [51.15.3.241]:35169
%(day)s 11:14:42 server postfix/smtpd[32097]: warning: hostname 51-15-3-241.rev.poneytelecom.eu does not resolve to address 51.15.3.241: Name or service not known
%(day)s 11:14:42 server postfix/smtpd[32097]: connect from unknown[51.15.3.241]
%(day)s 11:14:42 server postfix/smtpd[32097]: Anonymous TLS connection established from unknown[51.15.3.241]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
%(day)s 11:14:42 server postfix/smtpd[32097]: warning: 241.3.15.51.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=241.3.15.51.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:14:43 server policyd-spf[32112]: prepend Received-SPF: None (mailfrom) identity=mailfrom; client-ip=51.15.3.241; helo=intra.logikap.com; envelope-from=gitlab@intra.logikap.com; receiver=<UNKNOWN>
%(day)s 11:14:43 server postfix/smtpd[32097]: NOQUEUE: client=unknown[51.15.3.241]
%(day)s 11:14:45 server postfix/smtpd[32119]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:14:45 server postfix/smtpd[32119]: 339B2E00C3: client=localhost.localdomain[127.0.0.1], orig_client=unknown[51.15.3.241]
%(day)s 11:14:45 server postfix/cleanup[32120]: 339B2E00C3: message-id=<31819cf6c71e45f4569b94888ea90ead@gitlab.intra.logikap.com>
%(day)s 11:14:45 server postfix/smtpd[32119]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:14:45 server postfix/qmgr[26163]: 339B2E00C3: from=<gitlab@intra.logikap.com>, size=3772, nrcpt=1 (queue active)
%(day)s 11:14:45 server amavis[14540]: (14540-11) Passed CLEAN {RelayedInbound}, [51.15.3.241]:35169 [51.15.3.241] <gitlab@intra.logikap.com> -> <admin@test.com>, Message-ID: <31819cf6c71e45f4569b94888ea90ead@gitlab.intra.logikap.com>, Hits: -1.105, size: 3307, queued_as: 339B2E00C3, 1891 ms
%(day)s 11:14:45 server postfix/smtpd[32097]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 339B2E00C3; from=<gitlab@intra.logikap.com> to=<admin@test.com> proto=ESMTP helo=<intra.logikap.com>
%(day)s 11:14:45 server postfix/smtpd[32097]: disconnect from unknown[51.15.3.241] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
%(day)s 11:14:45 server dovecot: lmtp(32122): Connect from local
%(day)s 11:14:45 server dovecot: lmtp(admin@test.com): +NuIEBVlDVp6fQAABvoInA: sieve: msgid=<31819cf6c71e45f4569b94888ea90ead@gitlab.intra.logikap.com>: stored mail into mailbox 'INBOX'
%(day)s 11:14:45 server postfix/lmtp[32121]: 339B2E00C3: to=<admin@test.com>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.23, delays=0.06/0.01/0.01/0.16, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> +NuIEBVlDVp6fQAABvoInA Saved)
%(day)s 11:14:45 server dovecot: lmtp(32122): Disconnect from local: Successful quit
%(day)s 11:14:45 server postfix/qmgr[26163]: 339B2E00C3: removed
%(day)s 11:16:01 server dovecot: imap(admin@test.com): Logged out in=3056 out=66597
%(day)s 11:16:01 server dovecot: managesieve-login: Login: user=<admin@test.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=32316, secured, session=<efcy6BZeE8h/AAAB>
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: Loading modules from directory: /usr/lib/dovecot/modules
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: Module loaded: /usr/lib/dovecot/modules/lib10_quota_plugin.so
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: Added userdb setting: plugin/quota_rule=*:bytes=2048M
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: Effective uid=1010, gid=1010, home=/srv/vmail/ngyn.org/tonio
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: Quota root: name=User quota backend=dict args=:proxy::quota
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: Quota rule: root=User quota mailbox=* bytes=2147483648 messages=0
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: Quota grace: root=User quota bytes=214748364 (10%%)
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: dict quota: user=admin@test.com, uri=proxy::quota, noenforcing=0
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: Namespace inbox: type=private, prefix=, sep=, inbox=yes, hidden=no, list=yes, subscriptions=yes location=maildir:~/.maildir
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: maildir++: root=/srv/vmail/ngyn.org/tonio/.maildir, index=, indexpvt=, control=, inbox=/srv/vmail/ngyn.org/tonio/.maildir, alt=
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: quota: quota_over_flag check: STORAGE ret=1 value=989542 limit=2097152
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: quota: quota_over_flag check: MESSAGE ret=0 value=47722 limit=0
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: quota: quota_over_flag=0((null)) vs currently overquota=0
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: sieve: Pigeonhole version 0.4.16 (fed8554) initializing
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: sieve: file storage: Using active Sieve script path: /srv/vmail/ngyn.org/tonio/.dovecot.sieve
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: sieve: file storage: Using script storage path: /srv/vmail/ngyn.org/tonio/sieve
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: sieve: file storage: Using permissions from /srv/vmail/ngyn.org/tonio/sieve: mode=0750 gid=-1
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: sieve: file storage: Relative path to sieve storage in active link: sieve/
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Debug: sieve: file storage: sync: Synchronization active
%(day)s 11:16:01 server dovecot: managesieve(admin@test.com): Disconnected: Logged out bytes=6/41
%(day)s 11:16:01 server dovecot: imap-login: Login: user=<anomalie@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=32327, secured, session=<Tc826BZe1ch/AAAB>
%(day)s 11:16:01 server dovecot: imap(anomalie@test2.com): Logged out in=86 out=892
%(day)s 11:16:01 server dovecot: imap-login: Login: user=<evolution@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=32345, secured, session=<2d046BZe1sh/AAAB>
%(day)s 11:16:01 server dovecot: imap(evolution@test2.com): Logged out in=86 out=891
%(day)s 11:16:02 server dovecot: imap-login: Login: user=<question@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=32359, secured, session=<XWM66BZe28h/AAAB>
%(day)s 11:16:02 server dovecot: imap(question@test2.com): Logged out in=86 out=891
%(day)s 11:16:03 server postfix/postscreen[32096]: CONNECT from [81.92.113.114]:60750 to [94.23.45.181]:25
%(day)s 11:16:03 server postfix/postscreen[32096]: PASS OLD [81.92.113.114]:60750
%(day)s 11:16:03 server postfix/smtpd[32097]: connect from mta1.news.tarsus.fr[81.92.113.114]
%(day)s 11:16:03 server postfix/smtpd[32097]: warning: 114.113.92.81.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=114.113.92.81.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:16:03 server policyd-spf[32112]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=81.92.113.114; helo=mta1.news.tarsus.fr; envelope-from=marketing@info.opensourcesummit.paris; receiver=<UNKNOWN>
%(day)s 11:16:03 server postfix/smtpd[32097]: NOQUEUE: client=mta1.news.tarsus.fr[81.92.113.114]
%(day)s 11:16:04 server postfix/smtpd[32119]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:16:04 server postfix/smtpd[32119]: F39BCE00C3: client=localhost.localdomain[127.0.0.1], orig_client=mta1.news.tarsus.fr[81.92.113.114]
%(day)s 11:16:04 server postfix/cleanup[32120]: F39BCE00C3: message-id=<2.1.4.1101006021.4688801.152618499@info.opensourcesummit.paris>
%(day)s 11:16:05 server postfix/smtpd[32119]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:16:05 server postfix/qmgr[26163]: F39BCE00C3: from=<marketing@info.opensourcesummit.paris>, size=55627, nrcpt=1 (queue active)
%(day)s 11:16:05 server amavis[19749]: (19749-20) Passed CLEAN {RelayedInbound}, [81.92.113.114]:60750 [81.92.113.114] <marketing@info.opensourcesummit.paris> -> <user@test.com>, Message-ID: <2.1.4.1101006021.4688801.152618499@info.opensourcesummit.paris>, Hits: 3.698, size: 54587, queued_as: F39BCE00C3, dkim_sd=emv:info.opensourcesummit.paris, 1310 ms
%(day)s 11:16:05 server postfix/smtpd[32097]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as F39BCE00C3; from=<marketing@info.opensourcesummit.paris> to=<user@test.com> proto=ESMTP helo=<mta1.news.tarsus.fr>
%(day)s 11:16:05 server dovecot: lmtp(32392): Connect from local
%(day)s 11:16:05 server postfix/smtpd[32097]: disconnect from mta1.news.tarsus.fr[81.92.113.114] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5
%(day)s 11:16:05 server dovecot: lmtp(user@test.com): d8zmAmVlDVqIfgAABvoInA: sieve: msgid=<2.1.4.1101006021.4688801.152618499@info.opensourcesummit.paris>: stored mail into mailbox 'INBOX'
%(day)s 11:16:05 server postfix/lmtp[32121]: F39BCE00C3: to=<user@test.com>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.23, delays=0.04/0.01/0.01/0.17, dsn=2.0.0, status=sent (250 2.0.0 <user@test.com> d8zmAmVlDVqIfgAABvoInA Saved)
%(day)s 11:16:05 server dovecot: lmtp(32392): Disconnect from local: Successful quit
%(day)s 11:16:05 server postfix/qmgr[26163]: F39BCE00C3: removed
%(day)s 11:16:45 server dovecot: pop3-login: Login: user=<imhotep@koalabs.org>, method=PLAIN, rip=209.85.216.158, lip=94.23.45.181, mpid=32406, TLS, session=<AgHS6hZe1JnRVdie>
%(day)s 11:16:45 server dovecot: pop3(imhotep@koalabs.org): Disconnected: Logged out top=0/0, retr=0/0, del=0/141, size=8023766
%(day)s 11:17:01 server postfix/postscreen[32096]: CONNECT from [13.111.20.45]:47742 to [94.23.45.181]:25
%(day)s 11:17:01 server postfix/postscreen[32096]: WHITELISTED [13.111.20.45]:47742
%(day)s 11:17:01 server postfix/smtpd[32097]: connect from mta4.email.tfl.gov.uk[13.111.20.45]
%(day)s 11:17:02 server postfix/smtpd[32097]: Anonymous TLS connection established from mta4.email.tfl.gov.uk[13.111.20.45]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
%(day)s 11:17:02 server postfix/smtpd[32097]: warning: 45.20.111.13.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=45.20.111.13.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:17:03 server policyd-spf[32112]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=13.111.20.45; helo=mta4.email.tfl.gov.uk; envelope-from=bounce-150_html-21457874-18921-100001609-123@bounce.email.tfl.gov.uk; receiver=<UNKNOWN>
%(day)s 11:17:03 server postfix/smtpd[32097]: NOQUEUE: client=mta4.email.tfl.gov.uk[13.111.20.45]
%(day)s 11:17:06 server postfix/smtpd[32119]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:17:06 server postfix/smtpd[32119]: 9E1C3E00C3: client=localhost.localdomain[127.0.0.1], orig_client=mta4.email.tfl.gov.uk[13.111.20.45]
%(day)s 11:17:06 server postfix/cleanup[32120]: 9E1C3E00C3: message-id=<42e8ad52-02fb-45f5-a7fe-763c52409f6c@dfw1s10mta44.xt.local>
%(day)s 11:17:08 server postfix/smtpd[32119]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:17:08 server postfix/qmgr[26163]: 9E1C3E00C3: from=<bounce-150_HTML-21457874-18921-100001609-123@bounce.email.tfl.gov.uk>, size=71561, nrcpt=1 (queue active)
%(day)s 11:17:08 server amavis[5246]: (05246-17) Passed CLEAN {RelayedInbound}, [13.111.20.45]:47742 [13.111.20.45] <bounce-150_HTML-21457874-18921-100001609-123@bounce.email.tfl.gov.uk> -> <user@test.com>, Message-ID: <42e8ad52-02fb-45f5-a7fe-763c52409f6c@dfw1s10mta44.xt.local>, Hits: 2.492, size: 70304, queued_as: 9E1C3E00C3, dkim_sd=10dkim1:email.tfl.gov.uk, 3667 ms
%(day)s 11:17:08 server postfix/smtpd[32097]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 9E1C3E00C3; from=<bounce-150_HTML-21457874-18921-100001609-123@bounce.email.tfl.gov.uk> to=<user@test.com> proto=ESMTP helo=<mta4.email.tfl.gov.uk>
%(day)s 11:17:08 server dovecot: lmtp(32482): Connect from local
%(day)s 11:17:08 server dovecot: lmtp(user@test.com): +IarBqRlDVrifgAABvoInA: sieve: msgid=<42e8ad52-02fb-45f5-a7fe-763c52409f6c@dfw1s10mta44.xt.local>: stored mail into mailbox 'INBOX'
%(day)s 11:17:08 server postfix/lmtp[32121]: 9E1C3E00C3: to=<user@test.com>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=1.6, delays=1.5/0.01/0.01/0.17, dsn=2.0.0, status=sent (250 2.0.0 <user@test.com> +IarBqRlDVrifgAABvoInA Saved)
%(day)s 11:17:08 server dovecot: lmtp(32482): Disconnect from local: Successful quit
%(day)s 11:17:08 server postfix/qmgr[26163]: 9E1C3E00C3: removed
%(day)s 11:17:08 server postfix/smtpd[32097]: disconnect from mta4.email.tfl.gov.uk[13.111.20.45] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
%(day)s 11:17:27 server postfix/postscreen[32096]: CONNECT from [51.254.143.19]:34827 to [94.23.45.181]:25
%(day)s 11:17:33 server postfix/postscreen[32096]: NOQUEUE: reject: RCPT from [51.254.143.19]:34827: 450 4.3.2 Service currently unavailable; from=<szkoleniamanagerskie@machconsulting.eu>, to=<info@test2.com>, proto=ESMTP, helo=<vps373177.ovh.net>
%(day)s 11:17:33 server postfix/postscreen[32096]: PASS NEW [51.254.143.19]:34827
%(day)s 11:17:33 server postfix/postscreen[32096]: DISCONNECT [51.254.143.19]:34827
%(day)s 11:17:43 server postfix/postscreen[32096]: CONNECT from [172.110.9.131]:37348 to [94.23.45.181]:25
%(day)s 11:17:43 server postfix/postscreen[32096]: PASS OLD [172.110.9.131]:37348
%(day)s 11:17:43 server postfix/smtpd[32097]: connect from unknown[172.110.9.131]
%(day)s 11:17:43 server postfix/smtpd[32097]: Anonymous TLS connection established from unknown[172.110.9.131]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
%(day)s 11:17:43 server postfix/smtpd[32097]: warning: 131.9.110.172.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=131.9.110.172.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:17:44 server policyd-spf[32112]: prepend Received-SPF: None (no SPF record) identity=no SPF record; client-ip=172.110.9.131; helo=mailstore.paxi.cf; envelope-from=<>; receiver=<UNKNOWN>
%(day)s 11:17:44 server postfix/smtpd[32097]: NOQUEUE: client=unknown[172.110.9.131]
%(day)s 11:17:45 server postfix/smtpd[32119]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:17:45 server postfix/smtpd[32119]: 34B20E00C3: client=localhost.localdomain[127.0.0.1], orig_client=unknown[172.110.9.131]
%(day)s 11:17:45 server postfix/cleanup[32120]: 34B20E00C3: message-id=<20171116101742.C6A924DCECC6@mailstore.paxi.cf>
%(day)s 11:17:45 server postfix/smtpd[32119]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:17:45 server postfix/qmgr[26163]: 34B20E00C3: from=<>, size=4102, nrcpt=1 (queue active)
%(day)s 11:17:45 server amavis[21816]: (21816-20) Passed CLEAN {RelayedInbound}, [172.110.9.131]:37348 [172.110.9.131] <> -> <noreply@modoboa.org>, Message-ID: <20171116101742.C6A924DCECC6@mailstore.paxi.cf>, Hits: -1.106, size: 3626, queued_as: 34B20E00C3, 1017 ms
%(day)s 11:17:45 server dovecot: lmtp(32482): Connect from local
%(day)s 11:17:45 server postfix/smtpd[32097]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 34B20E00C3; from=<> to=<noreply@modoboa.org> proto=ESMTP helo=<mailstore.paxi.cf>
%(day)s 11:17:45 server dovecot: lmtp(admin@test.com): WQg7D8llDVrifgAABvoInA: sieve: msgid=<20171116101742.C6A924DCECC6@mailstore.paxi.cf>: not sending reject message to <>
%(day)s 11:17:45 server postfix/lmtp[32121]: 34B20E00C3: to=<admin@test.com>, orig_to=<noreply@modoboa.org>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.05, delays=0.04/0.01/0/0, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> WQg7D8llDVrifgAABvoInA Saved)
%(day)s 11:17:45 server dovecot: lmtp(32482): Disconnect from local: Successful quit
%(day)s 11:17:45 server postfix/qmgr[26163]: 34B20E00C3: removed
%(day)s 11:17:45 server postfix/postscreen[32096]: CONNECT from [108.174.3.154]:54018 to [94.23.45.181]:25
%(day)s 11:17:45 server postfix/postscreen[32096]: WHITELISTED [108.174.3.154]:54018
%(day)s 11:17:45 server postfix/smtpd[32097]: disconnect from unknown[172.110.9.131] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
%(day)s 11:17:45 server postfix/smtpd[32502]: connect from mailb-bb.linkedin.com[108.174.3.154]
%(day)s 11:17:45 server postfix/smtpd[32502]: Anonymous TLS connection established from mailb-bb.linkedin.com[108.174.3.154]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
%(day)s 11:17:46 server postfix/smtpd[32502]: warning: 154.3.174.108.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=154.3.174.108.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:17:46 server policyd-spf[32505]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=108.174.3.154; helo=mailb-bb.linkedin.com; envelope-from=m-i58nvfj318qraba58ra9m2nttnwbk7s0evxwduql0g5d0pa6k36@bounce.linkedin.com; receiver=<UNKNOWN>
%(day)s 11:17:46 server postfix/smtpd[32502]: NOQUEUE: client=mailb-bb.linkedin.com[108.174.3.154]
%(day)s 11:17:47 server postfix/postscreen[32096]: CONNECT from [81.92.113.115]:43100 to [94.23.45.181]:25
%(day)s 11:17:47 server postfix/postscreen[32096]: PASS OLD [81.92.113.115]:43100
%(day)s 11:17:47 server postfix/smtpd[32097]: connect from mta2.news.tarsus.fr[81.92.113.115]
%(day)s 11:17:47 server postfix/smtpd[32097]: warning: 115.113.92.81.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=115.113.92.81.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:17:48 server policyd-spf[32112]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=81.92.113.115; helo=mta2.news.tarsus.fr; envelope-from=marketing@info.opensourcesummit.paris; receiver=<UNKNOWN>
%(day)s 11:17:48 server postfix/smtpd[32097]: NOQUEUE: client=mta2.news.tarsus.fr[81.92.113.115]
%(day)s 11:17:52 server postfix/smtpd[32119]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:17:52 server postfix/smtpd[32119]: 69E9BE00C4: client=localhost.localdomain[127.0.0.1], orig_client=mailb-bb.linkedin.com[108.174.3.154]
%(day)s 11:17:52 server postfix/cleanup[32120]: 69E9BE00C4: message-id=<205549081.609208.1510827464487.JavaMail.app@lor1-app2315.prod.linkedin.com>
%(day)s 11:17:52 server postfix/smtpd[32119]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:17:52 server postfix/qmgr[26163]: 69E9BE00C4: from=<m-i58nvfj318qraba58ra9m2nttnwbk7s0evxwduql0g5d0pa6k36@bounce.linkedin.com>, size=35732, nrcpt=1 (queue active)
%(day)s 11:17:52 server amavis[14540]: (14540-12) Passed CLEAN {RelayedInbound}, [108.174.3.154]:54018 [108.174.3.154] <m-i58nvfj318qraba58ra9m2nttnwbk7s0evxwduql0g5d0pa6k36@bounce.linkedin.com> -> <user@test.com>, Message-ID: <205549081.609208.1510827464487.JavaMail.app@lor1-app2315.prod.linkedin.com>, Hits: -7.019, size: 35066, queued_as: 69E9BE00C4, dkim_sd=proddkim1024:linkedin.com,proddkim1024:mailb.linkedin.com, 5477 ms
%(day)s 11:17:52 server dovecot: lmtp(32482): Connect from local
%(day)s 11:17:52 server postfix/smtpd[32502]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 69E9BE00C4; from=<m-i58nvfj318qraba58ra9m2nttnwbk7s0evxwduql0g5d0pa6k36@bounce.linkedin.com> to=<user@test.com> proto=ESMTP helo=<mailb-bb.linkedin.com>
%(day)s 11:17:52 server dovecot: lmtp(user@test.com): UdRqG9BlDVrifgAABvoInA: sieve: msgid=<205549081.609208.1510827464487.JavaMail.app@lor1-app2315.prod.linkedin.com>: stored mail into mailbox 'INBOX'
%(day)s 11:17:52 server postfix/lmtp[32121]: 69E9BE00C4: to=<user@test.com>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.16, delays=0.03/0.01/0/0.13, dsn=2.0.0, status=sent (250 2.0.0 <user@test.com> UdRqG9BlDVrifgAABvoInA Saved)
%(day)s 11:17:52 server dovecot: lmtp(32482): Disconnect from local: Successful quit
%(day)s 11:17:52 server postfix/qmgr[26163]: 69E9BE00C4: removed
%(day)s 11:17:54 server postfix/smtpd[32119]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:17:54 server postfix/smtpd[32119]: 0EC0CE00C4: client=localhost.localdomain[127.0.0.1], orig_client=mta2.news.tarsus.fr[81.92.113.115]
%(day)s 11:17:54 server postfix/cleanup[32120]: 0EC0CE00C4: message-id=<2.1.4.1101006021.4688801.3909372752@info.opensourcesummit.paris>
%(day)s 11:17:54 server postfix/qmgr[26163]: 0EC0CE00C4: from=<marketing@info.opensourcesummit.paris>, size=55600, nrcpt=1 (queue active)
%(day)s 11:17:54 server amavis[32393]: (32393-01) Passed CLEAN {RelayedInbound}, [81.92.113.115]:43100 [81.92.113.115] <marketing@info.opensourcesummit.paris> -> <admin@test.com>, Message-ID: <2.1.4.1101006021.4688801.3909372752@info.opensourcesummit.paris>, Hits: 3.507, size: 54590, queued_as: 0EC0CE00C4, dkim_sd=emv:info.opensourcesummit.paris, 5899 ms
%(day)s 11:17:54 server dovecot: lmtp(32482): Connect from local
%(day)s 11:17:54 server postfix/smtpd[32097]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 0EC0CE00C4; from=<marketing@info.opensourcesummit.paris> to=<admin@test.com> proto=ESMTP helo=<mta2.news.tarsus.fr>
%(day)s 11:17:54 server postfix/smtpd[32097]: disconnect from mta2.news.tarsus.fr[81.92.113.115] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5
%(day)s 11:17:54 server dovecot: lmtp(admin@test.com): kRSZCNJlDVrifgAABvoInA: sieve: msgid=<2.1.4.1101006021.4688801.3909372752@info.opensourcesummit.paris>: stored mail into mailbox 'INBOX'
%(day)s 11:17:54 server postfix/lmtp[32121]: 0EC0CE00C4: to=<admin@test.com>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.26, delays=0.09/0.01/0/0.17, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> kRSZCNJlDVrifgAABvoInA Saved)
%(day)s 11:17:54 server dovecot: lmtp(32482): Disconnect from local: Successful quit
%(day)s 11:17:54 server postfix/qmgr[26163]: 0EC0CE00C4: removed
%(day)s 11:17:57 server postfix/smtpd[32502]: disconnect from mailb-bb.linkedin.com[108.174.3.154] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
%(day)s 11:18:26 server postfix/postscreen[32096]: CONNECT from [209.85.223.201]:46671 to [94.23.45.181]:25
%(day)s 11:18:26 server postfix/postscreen[32096]: WHITELISTED [209.85.223.201]:46671
%(day)s 11:18:26 server postfix/smtpd[32097]: connect from mail-io0-f201.google.com[209.85.223.201]
%(day)s 11:18:26 server postfix/smtpd[32097]: Anonymous TLS connection established from mail-io0-f201.google.com[209.85.223.201]: TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)
%(day)s 11:18:26 server postfix/smtpd[32097]: warning: 201.223.85.209.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=201.223.85.209.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:18:26 server postfix/cleanup[32120]: E8BF5E00C4: message-id=<20171116101826.E8BF5E00C4@mail.koalabs.org>
%(day)s 11:18:26 server postfix/qmgr[26163]: E8BF5E00C4: from=<double-bounce@mail.koalabs.org>, size=271, nrcpt=1 (queue active)
%(day)s 11:18:27 server postfix/pipe[32592]: E8BF5E00C4: to=<dmarc-aggrep@ngyn.org>, relay=dmarc-rua, delay=0.04, delays=0.03/0.01/0/0.01, dsn=2.0.0, status=deliverable (delivers to command: /srv/modoboa/env/bin/python)
%(day)s 11:18:27 server postfix/qmgr[26163]: E8BF5E00C4: removed
%(day)s 11:18:27 server policyd-spf[32112]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=209.85.223.201; helo=mail-io0-f201.google.com; envelope-from=noreply-dmarc-support@google.com; receiver=<UNKNOWN>
%(day)s 11:18:27 server postfix/smtpd[32097]: NOQUEUE: client=mail-io0-f201.google.com[209.85.223.201]
%(day)s 11:18:28 server postfix/smtpd[32601]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:18:28 server postfix/smtpd[32601]: 5E852E00C4: client=localhost.localdomain[127.0.0.1], orig_client=mail-io0-f201.google.com[209.85.223.201]
%(day)s 11:18:28 server postfix/cleanup[32120]: 5E852E00C4: message-id=<5520130506303437380@google.com>
%(day)s 11:18:28 server postfix/smtpd[32601]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:18:28 server postfix/qmgr[26163]: 5E852E00C4: from=<noreply-dmarc-support@google.com>, size=4390, nrcpt=1 (queue active)
%(day)s 11:18:28 server amavis[5246]: (05246-18) Passed CLEAN {RelayedInbound}, [209.85.223.201]:46671 [209.85.223.201] <noreply-dmarc-support@google.com> -> <dmarc-aggrep@ngyn.org>, Message-ID: <5520130506303437380@google.com>, Hits: 0.715, size: 3807, queued_as: 5E852E00C4, dkim_sd=20161025:google.com, 907 ms
%(day)s 11:18:28 server postfix/smtpd[32097]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 5E852E00C4; from=<noreply-dmarc-support@google.com> to=<dmarc-aggrep@ngyn.org> proto=ESMTP helo=<mail-io0-f201.google.com>
%(day)s 11:18:28 server postfix/smtpd[32097]: disconnect from mail-io0-f201.google.com[209.85.223.201] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
%(day)s 11:18:29 server postfix/pipe[32592]: 5E852E00C4: to=<dmarc-aggrep@ngyn.org>, relay=dmarc-rua, delay=0.85, delays=0.04/0/0/0.81, dsn=2.0.0, status=sent (delivered via dmarc-rua service (Importing report 5520130506303437380 received from google.com))
%(day)s 11:18:29 server postfix/qmgr[26163]: 5E852E00C4: removed
%(day)s 11:18:30 server postfix/postscreen[32096]: CONNECT from [193.105.248.56]:62968 to [94.23.45.181]:25
%(day)s 11:18:36 server postfix/tlsproxy[32611]: CONNECT from [193.105.248.56]:62968
%(day)s 11:18:38 server postfix/tlsproxy[32611]: Anonymous TLS connection established from [193.105.248.56]:62968: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
%(day)s 11:18:38 server postfix/postscreen[32096]: NOQUEUE: reject: RCPT from [193.105.248.56]:62968: 450 4.3.2 Service currently unavailable; from=<Kontakt@nestbank.pl>, to=<marcin.jurgielewicz@test2.com>, proto=ESMTP, helo=<mx01.nestbank.pl>
%(day)s 11:18:38 server postfix/postscreen[32096]: PASS NEW [193.105.248.56]:62968
%(day)s 11:18:38 server postfix/postscreen[32096]: DISCONNECT [193.105.248.56]:62968
%(day)s 11:18:38 server postfix/tlsproxy[32611]: DISCONNECT [193.105.248.56]:62968
%(day)s 11:19:59 server postfix/postscreen[32096]: CONNECT from [192.254.112.98]:6107 to [94.23.45.181]:25
%(day)s 11:19:59 server postfix/postscreen[32096]: WHITELISTED [192.254.112.98]:6107
%(day)s 11:19:59 server postfix/smtpd[32097]: connect from o3.sgmail.github.com[192.254.112.98]
%(day)s 11:19:59 server postfix/smtpd[32097]: Anonymous TLS connection established from o3.sgmail.github.com[192.254.112.98]: TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)
%(day)s 11:20:00 server postfix/smtpd[32097]: warning: 98.112.254.192.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=98.112.254.192.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:20:00 server policyd-spf[32112]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=192.254.112.98; helo=o3.sgmail.github.com; envelope-from=bounces+848413-16c5-tonio=ngyn.org@sgmail.github.com; receiver=<UNKNOWN>
%(day)s 11:20:00 server postfix/smtpd[32097]: NOQUEUE: client=o3.sgmail.github.com[192.254.112.98]
%(day)s 11:20:07 server postfix/smtpd[32601]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:20:07 server postfix/smtpd[32601]: D9EA5E00C3: client=localhost.localdomain[127.0.0.1], orig_client=o3.sgmail.github.com[192.254.112.98]
%(day)s 11:20:07 server postfix/cleanup[32120]: D9EA5E00C3: message-id=<Spicesoft/tandoori/pull/3047@github.com>
%(day)s 11:20:07 server postfix/smtpd[32601]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:20:07 server postfix/qmgr[26163]: D9EA5E00C3: from=<bounces+848413-16c5-tonio=ngyn.org@sgmail.github.com>, size=12574, nrcpt=1 (queue active)
%(day)s 11:20:07 server amavis[14540]: (14540-13) Passed CLEAN {RelayedInbound}, [192.254.112.98]:6107 [192.30.253.17] <bounces+848413-16c5-tonio=ngyn.org@sgmail.github.com> -> <admin@test.com>, Message-ID: <Spicesoft/tandoori/pull/3047@github.com>, Hits: -2.029, size: 11999, queued_as: D9EA5E00C3, dkim_sd=s20150108:github.com, 6918 ms
%(day)s 11:20:07 server postfix/smtpd[32097]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as D9EA5E00C3; from=<bounces+848413-16c5-tonio=ngyn.org@sgmail.github.com> to=<admin@test.com> proto=ESMTP helo=<o3.sgmail.github.com>
%(day)s 11:20:07 server dovecot: lmtp(323): Connect from local
%(day)s 11:20:08 server dovecot: lmtp(admin@test.com): ZLuaN1dmDVpDAQAABvoInA: sieve: msgid=<Spicesoft/tandoori/pull/3047@github.com>: stored mail into mailbox 'Listes.Tandoori'
%(day)s 11:20:08 server postfix/lmtp[322]: D9EA5E00C3: to=<admin@test.com>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.22, delays=0.03/0.01/0.01/0.17, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> ZLuaN1dmDVpDAQAABvoInA Saved)
%(day)s 11:20:08 server dovecot: lmtp(323): Disconnect from local: Successful quit
%(day)s 11:20:08 server postfix/qmgr[26163]: D9EA5E00C3: removed
%(day)s 11:20:09 server postfix/smtpd[32097]: disconnect from o3.sgmail.github.com[192.254.112.98] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
%(day)s 11:20:50 server dovecot: imap-login: Login: user=<admin@test.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=336, secured, session=<BOJl+RZeUcl/AAAB>
%(day)s 11:20:50 server dovecot: imap(admin@test.com): Logged out in=12 out=431
%(day)s 11:20:50 server dovecot: imap-login: Login: user=<admin@test.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=350, secured, session=<W99o+RZeVMl/AAAB>
%(day)s 11:20:50 server dovecot: imap(admin@test.com): Logged out in=12 out=431
%(day)s 11:21:48 server dovecot: imap-login: Login: user=<mowee@modoboa.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=436, secured, session=<ZYje/BZeXcl/AAAB>
%(day)s 11:21:48 server dovecot: imap(mowee@modoboa.com): Logged out in=12 out=431
%(day)s 11:22:01 server dovecot: imap-login: Login: user=<anomalie@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=514, secured, session=<zeWs/RZeYsl/AAAB>
%(day)s 11:22:01 server dovecot: imap(anomalie@test2.com): Logged out in=86 out=892
%(day)s 11:22:01 server dovecot: imap-login: Login: user=<evolution@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=526, secured, session=<UKKu/RZeY8l/AAAB>
%(day)s 11:22:02 server dovecot: imap(evolution@test2.com): Logged out in=86 out=891
%(day)s 11:22:02 server dovecot: imap-login: Login: user=<question@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=538, secured, session=<jSmw/RZeZMl/AAAB>
%(day)s 11:22:02 server dovecot: imap(question@test2.com): Logged out in=86 out=891
%(day)s 11:22:54 server postfix/smtpd[32119]: timeout after END-OF-MESSAGE from localhost.localdomain[127.0.0.1]
%(day)s 11:22:54 server postfix/smtpd[32119]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 commands=5
%(day)s 11:23:29 server postfix/anvil[32099]: statistics: max connection rate 1/60s for (smtpd:51.15.3.241) at %(day)s 11:14:42
%(day)s 11:23:29 server postfix/anvil[32099]: statistics: max connection count 1 for (smtpd:51.15.3.241) at %(day)s 11:14:42
%(day)s 11:23:29 server postfix/anvil[32099]: statistics: max cache size 4 at %(day)s 11:17:47
%(day)s 11:26:26 server postfix/postscreen[916]: CONNECT from [167.89.55.170]:3520 to [94.23.45.181]:25
%(day)s 11:26:26 server postfix/postscreen[916]: WHITELISTED [167.89.55.170]:3520
%(day)s 11:26:26 server postfix/smtpd[917]: connect from o9.sendgrid.meetup.com[167.89.55.170]
%(day)s 11:26:27 server postfix/smtpd[917]: Anonymous TLS connection established from o9.sendgrid.meetup.com[167.89.55.170]: TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)
%(day)s 11:26:28 server postfix/smtpd[917]: warning: 170.55.89.167.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=170.55.89.167.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:26:28 server policyd-spf[932]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=167.89.55.170; helo=o9.sendgrid.meetup.com; envelope-from=bounces+3922699-145a-tonio=ngyn.org@sendgrid.meetup.com; receiver=<UNKNOWN>
%(day)s 11:26:28 server postfix/smtpd[917]: NOQUEUE: client=o9.sendgrid.meetup.com[167.89.55.170]
%(day)s 11:26:36 server postfix/smtpd[944]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:26:36 server postfix/smtpd[944]: 61F9DE00C3: client=localhost.localdomain[127.0.0.1], orig_client=o9.sendgrid.meetup.com[167.89.55.170]
%(day)s 11:26:36 server postfix/cleanup[945]: 61F9DE00C3: message-id=<710800146.1510827986412.JavaMail.root@1c1b55d0dbe0>
%(day)s 11:26:36 server postfix/smtpd[944]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:26:36 server postfix/qmgr[26163]: 61F9DE00C3: from=<bounces+3922699-145a-tonio=ngyn.org@sendgrid.meetup.com>, size=72067, nrcpt=1 (queue active)
%(day)s 11:26:36 server amavis[32393]: (32393-02) Passed CLEAN {RelayedInbound}, [167.89.55.170]:3520 [34.196.236.240] <bounces+3922699-145a-tonio=ngyn.org@sendgrid.meetup.com> -> <admin@test.com>, Message-ID: <710800146.1510827986412.JavaMail.root@1c1b55d0dbe0>, Hits: -2.221, size: 71500, queued_as: 61F9DE00C3, dkim_sd=s1:meetup.com, 7334 ms
%(day)s 11:26:36 server postfix/smtpd[917]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 61F9DE00C3; from=<bounces+3922699-145a-tonio=ngyn.org@sendgrid.meetup.com> to=<admin@test.com> proto=ESMTP helo=<o9.sendgrid.meetup.com>
%(day)s 11:26:36 server dovecot: lmtp(947): Connect from local
%(day)s 11:26:36 server dovecot: lmtp(admin@test.com): f7GkHNxnDVqzAwAABvoInA: sieve: msgid=<710800146.1510827986412.JavaMail.root@1c1b55d0dbe0>: stored mail into mailbox 'INBOX'
%(day)s 11:26:36 server postfix/lmtp[946]: 61F9DE00C3: to=<admin@test.com>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.28, delays=0.07/0.01/0.01/0.19, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> f7GkHNxnDVqzAwAABvoInA Saved)
%(day)s 11:26:36 server dovecot: lmtp(947): Disconnect from local: Successful quit
%(day)s 11:26:36 server postfix/qmgr[26163]: 61F9DE00C3: removed
%(day)s 11:26:38 server postfix/smtpd[917]: disconnect from o9.sendgrid.meetup.com[167.89.55.170] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
%(day)s 11:28:01 server dovecot: imap-login: Login: user=<anomalie@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=1109, secured, session=<CnAfExdevsl/AAAB>
%(day)s 11:28:01 server dovecot: imap(anomalie@test2.com): Logged out in=86 out=892
%(day)s 11:28:01 server dovecot: imap-login: Login: user=<evolution@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=1125, secured, session=<fhohExdev8l/AAAB>
%(day)s 11:28:01 server dovecot: imap(evolution@test2.com): Logged out in=86 out=891
%(day)s 11:28:01 server dovecot: imap-login: Login: user=<question@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=1137, secured, session=<+4AiExdewMl/AAAB>
%(day)s 11:28:01 server dovecot: imap(question@test2.com): Logged out in=86 out=891
%(day)s 11:29:58 server postfix/anvil[919]: statistics: max connection rate 1/60s for (smtpd:167.89.55.170) at %(day)s 11:26:26
%(day)s 11:29:58 server postfix/anvil[919]: statistics: max connection count 1 for (smtpd:167.89.55.170) at %(day)s 11:26:26
%(day)s 11:29:58 server postfix/anvil[919]: statistics: max cache size 1 at %(day)s 11:26:26
%(day)s 11:30:30 server dovecot: imap-login: Login: user=<admin@test.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=1406, secured, session=<CJn8Gxde5cl/AAAB>
%(day)s 11:30:30 server dovecot: imap(admin@test.com): Logged out in=12 out=431
%(day)s 11:30:30 server dovecot: imap-login: Login: user=<admin@test.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=1420, secured, session=<rR4AHBde6Ml/AAAB>
%(day)s 11:30:30 server dovecot: imap(admin@test.com): Logged out in=12 out=431
%(day)s 11:30:34 server dovecot: imap-login: Login: user=<admin@test.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=1436, secured, session=<lPE2HBde6cl/AAAB>
%(day)s 11:30:34 server dovecot: imap(admin@test.com): Logged out in=12 out=431
%(day)s 11:30:34 server dovecot: imap-login: Login: user=<admin@test.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=1448, secured, session=<rfA6HBde6sl/AAAB>
%(day)s 11:30:34 server dovecot: imap(admin@test.com): Logged out in=12 out=431
%(day)s 11:32:47 server postfix/postscreen[1625]: CONNECT from [197.155.150.177]:16256 to [94.23.45.181]:25
%(day)s 11:32:59 server postfix/postscreen[1625]: NOQUEUE: reject: RCPT from [197.155.150.177]:16256: 450 4.3.2 Service currently unavailable; from=<sion@sicli.ch>, to=<andrzej.patejuk@test2.com>, proto=ESMTP, helo=<[197.155.150.177]>
%(day)s 11:32:59 server postfix/postscreen[1625]: HANGUP after 6.6 from [197.155.150.177]:16256 in tests after SMTP handshake
%(day)s 11:32:59 server postfix/postscreen[1625]: PASS NEW [197.155.150.177]:16256
%(day)s 11:32:59 server postfix/postscreen[1625]: DISCONNECT [197.155.150.177]:16256
%(day)s 11:34:02 server dovecot: imap-login: Login: user=<anomalie@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=1769, secured, session=<EIWbKBdeCMp/AAAB>
%(day)s 11:34:02 server dovecot: imap(anomalie@test2.com): Logged out in=86 out=892
%(day)s 11:34:02 server dovecot: imap-login: Login: user=<evolution@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=1785, secured, session=<rDGdKBdeCcp/AAAB>
%(day)s 11:34:02 server dovecot: imap(evolution@test2.com): Logged out in=86 out=891
%(day)s 11:34:02 server dovecot: imap-login: Login: user=<question@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=1797, secured, session=<8peeKBdeCsp/AAAB>
%(day)s 11:34:02 server dovecot: imap(question@test2.com): Logged out in=86 out=891
%(day)s 11:35:07 server postfix/postscreen[1912]: CONNECT from [14.173.93.73]:55595 to [94.23.45.181]:25
%(day)s 11:35:14 server postfix/postscreen[1912]: NOQUEUE: reject: RCPT from [14.173.93.73]:55595: 450 4.3.2 Service currently unavailable; from=<srdjan.sipus@sk.t-com.hr>, to=<andrzej.patejuk@test2.com>, proto=ESMTP, helo=<static.vnpt.vn>
%(day)s 11:35:15 server postfix/postscreen[1912]: HANGUP after 1.4 from [14.173.93.73]:55595 in tests after SMTP handshake
%(day)s 11:35:15 server postfix/postscreen[1912]: PASS NEW [14.173.93.73]:55595
%(day)s 11:35:15 server postfix/postscreen[1912]: DISCONNECT [14.173.93.73]:55595
%(day)s 11:36:00 server postfix/postscreen[1912]: CONNECT from [185.83.51.33]:58639 to [94.23.45.181]:25
%(day)s 11:36:06 server postfix/tlsproxy[2011]: CONNECT from [185.83.51.33]:58639
%(day)s 11:36:06 server postfix/tlsproxy[2011]: Anonymous TLS connection established from [185.83.51.33]:58639: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
%(day)s 11:36:07 server postfix/postscreen[1912]: NOQUEUE: reject: RCPT from [185.83.51.33]:58639: 450 4.3.2 Service currently unavailable; from=<mailreturn@smtp24.ymlpsvr.com>, to=<comercial@jm-motores.es>, proto=ESMTP, helo=<smtp24.ymlpsvr.com>
%(day)s 11:36:07 server postfix/postscreen[1912]: PASS NEW [185.83.51.33]:58639
%(day)s 11:36:07 server postfix/tlsproxy[2011]: DISCONNECT [185.83.51.33]:58639
%(day)s 11:36:07 server postfix/postscreen[1912]: DISCONNECT [185.83.51.33]:58639
%(day)s 11:36:45 server postfix/postscreen[1912]: CONNECT from [185.5.53.87]:50522 to [94.23.45.181]:25
%(day)s 11:36:45 server postfix/postscreen[1912]: PASS OLD [185.5.53.87]:50522
%(day)s 11:36:45 server postfix/smtpd[2027]: connect from main.nope.org.es[185.5.53.87]
%(day)s 11:36:45 server postfix/smtpd[2027]: Anonymous TLS connection established from main.nope.org.es[185.5.53.87]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
%(day)s 11:36:46 server postfix/smtpd[2027]: warning: 87.53.5.185.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=87.53.5.185.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:36:46 server policyd-spf[2042]: prepend Received-SPF: None (no SPF record) identity=no SPF record; client-ip=185.5.53.87; helo=main.nope.org.es; envelope-from=<>; receiver=<UNKNOWN>
%(day)s 11:36:46 server postfix/smtpd[2027]: NOQUEUE: client=main.nope.org.es[185.5.53.87]
%(day)s 11:36:47 server postfix/smtpd[2051]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:36:47 server postfix/smtpd[2051]: E0B74E00C3: client=localhost.localdomain[127.0.0.1], orig_client=main.nope.org.es[185.5.53.87]
%(day)s 11:36:47 server postfix/cleanup[2052]: E0B74E00C3: message-id=<201711161036.vAGAajZS022777@main.nope.org.es>
%(day)s 11:36:47 server postfix/smtpd[2051]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:36:47 server postfix/qmgr[26163]: E0B74E00C3: from=<>, size=3195, nrcpt=1 (queue active)
%(day)s 11:36:47 server amavis[14540]: (14540-14) Passed CLEAN {RelayedInbound}, [185.5.53.87]:50522 [185.5.53.87] <> -> <noreply@modoboa.org>, Message-ID: <201711161036.vAGAajZS022777@main.nope.org.es>, Hits: -1.889, size: 2719, queued_as: E0B74E00C3, 1212 ms
%(day)s 11:36:47 server postfix/smtpd[2027]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as E0B74E00C3; from=<> to=<noreply@modoboa.org> proto=ESMTP helo=<main.nope.org.es>
%(day)s 11:36:47 server dovecot: lmtp(2054): Connect from local
%(day)s 11:36:47 server dovecot: lmtp(admin@test.com): e4pnOj9qDVoGCAAABvoInA: sieve: msgid=<201711161036.vAGAajZS022777@main.nope.org.es>: not sending reject message to <>
%(day)s 11:36:47 server dovecot: lmtp(2054): Disconnect from local: Successful quit
%(day)s 11:36:47 server postfix/lmtp[2053]: E0B74E00C3: to=<admin@test.com>, orig_to=<noreply@modoboa.org>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.08, delays=0.05/0.01/0.01/0.01, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> e4pnOj9qDVoGCAAABvoInA Saved)
%(day)s 11:36:47 server postfix/qmgr[26163]: E0B74E00C3: removed
%(day)s 11:36:48 server policyd-spf[2042]: prepend Received-SPF: None (no SPF record) identity=no SPF record; client-ip=185.5.53.87; helo=main.nope.org.es; envelope-from=<>; receiver=<UNKNOWN>
%(day)s 11:36:48 server postfix/smtpd[2027]: NOQUEUE: client=main.nope.org.es[185.5.53.87]
%(day)s 11:36:49 server postfix/smtpd[2051]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:36:49 server postfix/smtpd[2051]: 62D9BE00C3: client=localhost.localdomain[127.0.0.1], orig_client=main.nope.org.es[185.5.53.87]
%(day)s 11:36:49 server postfix/cleanup[2052]: 62D9BE00C3: message-id=<201711161036.vAGAajZT022777@main.nope.org.es>
%(day)s 11:36:49 server postfix/smtpd[2051]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:36:49 server postfix/qmgr[26163]: 62D9BE00C3: from=<>, size=2989, nrcpt=1 (queue active)
%(day)s 11:36:49 server dovecot: lmtp(2054): Connect from local
%(day)s 11:36:49 server dovecot: lmtp(admin@test.com): aVPzGUFqDVoGCAAABvoInA: sieve: msgid=<201711161036.vAGAajZT022777@main.nope.org.es>: not sending reject message to <>
%(day)s 11:36:49 server postfix/lmtp[2053]: 62D9BE00C3: to=<admin@test.com>, orig_to=<noreply@modoboa.org>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.03, delays=0.03/0/0/0, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> aVPzGUFqDVoGCAAABvoInA Saved)
%(day)s 11:36:49 server dovecot: lmtp(2054): Disconnect from local: Successful quit
%(day)s 11:36:49 server postfix/qmgr[26163]: 62D9BE00C3: removed
%(day)s 11:36:49 server amavis[32393]: (32393-03) Passed CLEAN {RelayedInbound}, [185.5.53.87]:50522 [185.5.53.87] <> -> <noreply@modoboa.org>, Message-ID: <201711161036.vAGAajZT022777@main.nope.org.es>, Hits: -1.889, size: 2513, queued_as: 62D9BE00C3, 955 ms
%(day)s 11:36:49 server postfix/smtpd[2027]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 62D9BE00C3; from=<> to=<noreply@modoboa.org> proto=ESMTP helo=<main.nope.org.es>
%(day)s 11:36:49 server postfix/smtpd[2027]: disconnect from main.nope.org.es[185.5.53.87] ehlo=2 starttls=1 mail=2 rcpt=2 data=2 rset=1 quit=1 commands=11
%(day)s 11:38:49 server dovecot: imap-login: Login: user=<mowee@modoboa.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=2280, secured, session=<x0i8ORdeUsp/AAAB>
%(day)s 11:38:49 server dovecot: imap(mowee@modoboa.com): Logged out in=12 out=431
%(day)s 11:40:02 server dovecot: imap-login: Login: user=<anomalie@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=2474, secured, session=<MyUUPhdeYsp/AAAB>
%(day)s 11:40:02 server dovecot: imap(anomalie@test2.com): Logged out in=86 out=892
%(day)s 11:40:02 server dovecot: imap-login: Login: user=<evolution@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=2490, secured, session=<oScWPhdeZcp/AAAB>
%(day)s 11:40:02 server dovecot: imap(evolution@test2.com): Logged out in=86 out=891
%(day)s 11:40:02 server dovecot: imap-login: Login: user=<question@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=2502, secured, session=<3Y0XPhdeZsp/AAAB>
%(day)s 11:40:02 server dovecot: imap(question@test2.com): Logged out in=86 out=891
%(day)s 11:40:09 server postfix/anvil[2029]: statistics: max connection rate 1/60s for (smtpd:185.5.53.87) at %(day)s 11:36:45
%(day)s 11:40:09 server postfix/anvil[2029]: statistics: max connection count 1 for (smtpd:185.5.53.87) at %(day)s 11:36:45
%(day)s 11:40:09 server postfix/anvil[2029]: statistics: max cache size 1 at %(day)s 11:36:45
%(day)s 11:43:42 server dovecot: imap(admin@test.com): Disconnected for inactivity in=1797 out=54357
%(day)s 11:44:20 server postfix/postscreen[2852]: CONNECT from [192.254.113.101]:53977 to [94.23.45.181]:25
%(day)s 11:44:20 server postfix/postscreen[2852]: WHITELISTED [192.254.113.101]:53977
%(day)s 11:44:20 server postfix/smtpd[2853]: connect from o6.sgmail.github.com[192.254.113.101]
%(day)s 11:44:20 server postfix/smtpd[2853]: Anonymous TLS connection established from o6.sgmail.github.com[192.254.113.101]: TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)
%(day)s 11:44:21 server postfix/smtpd[2853]: warning: 101.113.254.192.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=101.113.254.192.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:44:21 server policyd-spf[2868]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=192.254.113.101; helo=o6.sgmail.github.com; envelope-from=bounces+848413-16c5-tonio=ngyn.org@sgmail.github.com; receiver=<UNKNOWN>
%(day)s 11:44:21 server postfix/smtpd[2853]: NOQUEUE: client=o6.sgmail.github.com[192.254.113.101]
%(day)s 11:44:31 server postfix/smtpd[2878]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:44:31 server postfix/smtpd[2878]: 70959E00C3: client=localhost.localdomain[127.0.0.1], orig_client=o6.sgmail.github.com[192.254.113.101]
%(day)s 11:44:31 server postfix/cleanup[2879]: 70959E00C3: message-id=<Spicesoft/tandoori/pull/3047/c344885124@github.com>
%(day)s 11:44:31 server postfix/smtpd[2878]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:44:31 server postfix/qmgr[26163]: 70959E00C3: from=<bounces+848413-16c5-tonio=ngyn.org@sgmail.github.com>, size=9954, nrcpt=1 (queue active)
%(day)s 11:44:31 server amavis[14540]: (14540-15) Passed CLEAN {RelayedInbound}, [192.254.113.101]:53977 [192.30.253.16] <bounces+848413-16c5-tonio=ngyn.org@sgmail.github.com> -> <admin@test.com>, Message-ID: <Spicesoft/tandoori/pull/3047/c344885124@github.com>, Hits: -2.22, size: 9378, queued_as: 70959E00C3, dkim_sd=s20150108:github.com, 9468 ms
%(day)s 11:44:31 server postfix/smtpd[2853]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as 70959E00C3; from=<bounces+848413-16c5-tonio=ngyn.org@sgmail.github.com> to=<admin@test.com> proto=ESMTP helo=<o6.sgmail.github.com>
%(day)s 11:44:31 server dovecot: lmtp(2881): Connect from local
%(day)s 11:44:31 server dovecot: lmtp(admin@test.com): FmU3Hg9sDVpBCwAABvoInA: sieve: msgid=<Spicesoft/tandoori/pull/3047/c344885124@github.com>: stored mail into mailbox 'Listes.Tandoori'
%(day)s 11:44:31 server postfix/lmtp[2880]: 70959E00C3: to=<admin@test.com>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.2, delays=0.04/0.01/0.01/0.14, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> FmU3Hg9sDVpBCwAABvoInA Saved)
%(day)s 11:44:31 server dovecot: lmtp(2881): Disconnect from local: Successful quit
%(day)s 11:44:31 server postfix/qmgr[26163]: 70959E00C3: removed
%(day)s 11:44:33 server postfix/smtpd[2853]: disconnect from o6.sgmail.github.com[192.254.113.101] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
%(day)s 11:46:01 server dovecot: imap-login: Login: user=<anomalie@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=3041, secured, session=<wWyAUxdeusp/AAAB>
%(day)s 11:46:01 server dovecot: imap(anomalie@test2.com): Logged out in=86 out=892
%(day)s 11:46:01 server dovecot: imap-login: Login: user=<evolution@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=3057, secured, session=<YASCUxdeu8p/AAAB>
%(day)s 11:46:01 server dovecot: imap(evolution@test2.com): Logged out in=86 out=891
%(day)s 11:46:01 server dovecot: imap-login: Login: user=<question@test2.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=3069, secured, session=<6mqDUxdevMp/AAAB>
%(day)s 11:46:02 server dovecot: imap(question@test2.com): Logged out in=86 out=891
%(day)s 11:47:16 server postfix/postscreen[3161]: CONNECT from [37.187.155.42]:33450 to [94.23.45.181]:25
%(day)s 11:47:22 server postfix/tlsproxy[3164]: CONNECT from [37.187.155.42]:33450
%(day)s 11:47:22 server postfix/tlsproxy[3164]: Anonymous TLS connection established from [37.187.155.42]:33450: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
%(day)s 11:47:22 server postfix/postscreen[3161]: NOQUEUE: reject: RCPT from [37.187.155.42]:33450: 450 4.3.2 Service currently unavailable; from=<rebotes@cursosfemxa.es>, to=<comercial@jm-motores.es>, proto=ESMTP, helo=<cursosfemxa.es>
%(day)s 11:47:22 server postfix/postscreen[3161]: PASS NEW [37.187.155.42]:33450
%(day)s 11:47:22 server postfix/postscreen[3161]: DISCONNECT [37.187.155.42]:33450
%(day)s 11:47:22 server postfix/tlsproxy[3164]: DISCONNECT [37.187.155.42]:33450
%(day)s 11:47:42 server postfix/postscreen[3161]: CONNECT from [172.110.9.131]:58398 to [94.23.45.181]:25
%(day)s 11:47:42 server postfix/postscreen[3161]: PASS OLD [172.110.9.131]:58398
%(day)s 11:47:43 server postfix/smtpd[3182]: connect from unknown[172.110.9.131]
%(day)s 11:47:43 server postfix/smtpd[3182]: Anonymous TLS connection established from unknown[172.110.9.131]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
%(day)s 11:47:43 server postfix/smtpd[3182]: warning: 131.9.110.172.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=131.9.110.172.zen.spamhaus.org type=A: Host not found, try again
%(day)s 11:47:44 server policyd-spf[3195]: prepend Received-SPF: None (no SPF record) identity=no SPF record; client-ip=172.110.9.131; helo=mailstore.paxi.cf; envelope-from=<>; receiver=<UNKNOWN>
%(day)s 11:47:44 server postfix/smtpd[3182]: NOQUEUE: client=unknown[172.110.9.131]
%(day)s 11:47:45 server postfix/smtpd[3202]: connect from localhost.localdomain[127.0.0.1]
%(day)s 11:47:45 server postfix/smtpd[3202]: E81D5E00C3: client=localhost.localdomain[127.0.0.1], orig_client=unknown[172.110.9.131]
%(day)s 11:47:45 server postfix/cleanup[3203]: E81D5E00C3: message-id=<20171116104742.7CC0E4DCECC7@mailstore.paxi.cf>
%(day)s 11:47:45 server postfix/smtpd[3202]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 11:47:45 server postfix/qmgr[26163]: E81D5E00C3: from=<>, size=4166, nrcpt=1 (queue active)
%(day)s 11:47:45 server amavis[32393]: (32393-04) Passed CLEAN {RelayedInbound}, [172.110.9.131]:58398 [172.110.9.131] <> -> <noreply@modoboa.org>, Message-ID: <20171116104742.7CC0E4DCECC7@mailstore.paxi.cf>, Hits: -1.106, size: 3690, queued_as: E81D5E00C3, 1410 ms
%(day)s 11:47:45 server postfix/smtpd[3182]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as E81D5E00C3; from=<> to=<noreply@modoboa.org> proto=ESMTP helo=<mailstore.paxi.cf>
%(day)s 11:47:46 server dovecot: lmtp(3205): Connect from local
%(day)s 11:47:46 server dovecot: lmtp(admin@test.com): RTETANJsDVqFDAAABvoInA: sieve: msgid=<20171116104742.7CC0E4DCECC7@mailstore.paxi.cf>: not sending reject message to <>
%(day)s 11:47:46 server postfix/lmtp[3204]: E81D5E00C3: to=<admin@test.com>, orig_to=<noreply@modoboa.org>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.07, delays=0.04/0.01/0.01/0, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> RTETANJsDVqFDAAABvoInA Saved)
%(day)s 11:47:46 server dovecot: lmtp(3205): Disconnect from local: Successful quit
%(day)s 11:47:46 server postfix/qmgr[26163]: E81D5E00C3: removed
%(day)s 11:47:46 server postfix/smtpd[3182]: disconnect from unknown[172.110.9.131] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
%(day)s 11:50:50 server dovecot: imap-login: Login: user=<admin@test.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=3536, secured, session=<PwOvZBdeI8t/AAAB>
%(day)s 11:50:50 server dovecot: imap(admin@test.com): Logged out in=12 out=431
%(day)s 11:50:50 server dovecot: imap-login: Login: user=<admin@test.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, mpid=3551, secured, session=<0rGyZBdeJst/AAAB>
%(day)s 11:50:50 server dovecot: imap(admin@test.com): Logged out in=12 out=431
%(day)s 14:40:58 server postfix/postscreen[27044]: CONNECT from [188.213.142.238]:42388 to [94.23.45.181]:25
%(day)s 14:40:58 server postfix/postscreen[27044]: PASS OLD [188.213.142.238]:42388
%(day)s 14:40:58 server postfix/smtpd[27045]: connect from c264-2.lesmails.info[188.213.142.238]
%(day)s 14:40:58 server postfix/smtpd[27045]: warning: 238.142.213.188.zen.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=238.142.213.188.zen.spamhaus.org type=A: Host not found, try again
%(day)s 14:40:59 server policyd-spf[27066]: prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=188.213.142.238; helo=sender.234.com; envelope-from=no-reply@mailing-lowcost.fr; receiver=<UNKNOWN>
%(day)s 14:40:59 server postfix/smtpd[27045]: NOQUEUE: client=c264-2.lesmails.info[188.213.142.238]
%(day)s 14:41:00 server postfix/smtpd[27073]: connect from localhost.localdomain[127.0.0.1]
%(day)s 14:41:00 server postfix/smtpd[27073]: C2E3BE00C3: client=localhost.localdomain[127.0.0.1], orig_client=c264-2.lesmails.info[188.213.142.238]
%(day)s 14:41:00 server postfix/cleanup[27074]: C2E3BE00C3: message-id=<20171116131143.F75320333C@JM6_EVENTS.home>
%(day)s 14:41:00 server postfix/smtpd[27073]: disconnect from localhost.localdomain[127.0.0.1] ehlo=1 xforward=1 mail=1 rcpt=1 data=1 quit=1 commands=6
%(day)s 14:41:00 server postfix/qmgr[26163]: C2E3BE00C3: from=<no-reply@mailing-lowcost.fr>, size=97952, nrcpt=1 (queue active)
%(day)s 14:41:00 server amavis[8518]: (08518-10) Passed SPAM {RelayedTaggedInbound}, [188.213.142.238]:42388 [188.213.142.238] <no-reply@mailing-lowcost.fr> -> <alias@test.com>, Message-ID: <20171116131143.F75320333C@jm6_events.home>, Hits: 13.086, size: 96743, queued_as: C2E3BE00C3, 1258 ms
%(day)s 14:41:00 server postfix/smtpd[27045]: proxy-accept: END-OF-MESSAGE: 250 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as C2E3BE00C3; from=<no-reply@mailing-lowcost.fr> to=<alias@test.com> proto=ESMTP helo=<sender.234.com>
%(day)s 14:41:00 server postfix/smtpd[27045]: disconnect from c264-2.lesmails.info[188.213.142.238] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5
%(day)s 14:41:00 server dovecot: lmtp(27260): Connect from local
%(day)s 14:41:01 server dovecot: lmtp(admin@test.com): +TSvNWyVDVp8agAABvoInA: sieve: msgid=<20171116131143.F75320333C@JM6_EVENTS.home>: stored mail into mailbox 'Junk'
%(day)s 14:41:01 server postfix/lmtp[27075]: C2E3BE00C3: to=<admin@test.com>, orig_to=<alias@test.com>, relay=mail.koalabs.org[private/dovecot-lmtp], delay=0.29, delays=0.09/0.01/0.01/0.18, dsn=2.0.0, status=sent (250 2.0.0 <admin@test.com> +TSvNWyVDVp8agAABvoInA Saved)
%(day)s 14:41:01 server dovecot: lmtp(27260): Disconnect from local: Successful quit
%(day)s 14:41:01 server postfix/qmgr[26163]: C2E3BE00C3: removed
+168
View File
@@ -0,0 +1,168 @@
"""modoboa-stats tests."""
import datetime
import os
import shutil
import tempfile
from django.core.management import call_command
from django.urls import reverse
from django.test import override_settings
from modoboa.admin import factories as admin_factories
from modoboa.core import models as core_models
from modoboa.lib.tests import ModoTestCase
class RunCommandsMixin(object):
"""Mixin to run management commands."""
def setUp(self):
super(RunCommandsMixin, self).setUp()
self.workdir = tempfile.mkdtemp()
self.set_global_parameter("rrd_rootdir", self.workdir)
def tearDown(self):
shutil.rmtree(self.workdir)
def run_logparser(self):
"""Run logparser command."""
path = os.path.join(
os.path.dirname(__file__), "mail.log")
with open(path) as fp:
content = fp.read() % {
"day": datetime.date.today().strftime("%b %d")}
path = os.path.join(self.workdir, "mail.log")
with open(path, "w") as fp:
fp.write(content)
self.set_global_parameter("logfile", path)
call_command("logparser")
def run_update_statistics(self, rebuild=False):
"""Run update_statistics command."""
args = []
if rebuild:
args.append("--rebuild")
call_command("update_statistics", *args)
@override_settings(RRDTOOL_TEST_MODE=True)
class ViewsTestCase(RunCommandsMixin, ModoTestCase):
"""Views test cases."""
@classmethod
def setUpTestData(cls): # noqa
super(ViewsTestCase, cls).setUpTestData()
admin_factories.populate_database()
cls.da = core_models.User.objects.get(username="admin@test.com")
def tearDown(self):
super(ViewsTestCase, self).tearDown()
self.set_global_parameter("greylist", False)
def test_index(self):
"""Test index view."""
url = reverse("maillog:fullindex")
response = self.client.get(url)
self.assertContains(response, 'id="graphs_accountgraphicset"')
self.assertContains(response, 'id="graphs_mailtraffic"')
self.client.force_login(self.da)
response = self.client.get(url)
self.assertContains(response, 'id="graphs_mailtraffic"')
def test_graphs(self):
"""Test graphs views."""
self.run_logparser()
url = reverse("maillog:graph_list")
self.ajax_get(url, status=404)
response = self.ajax_get("{}?gset=mailtraffic".format(url))
self.assertIn("averagetraffic", response["graphs"])
for period in ["week", "month", "year"]:
response = self.ajax_get(
"{}?gset=mailtraffic&period={}".format(url, period))
self.assertIn("averagetraffic", response["graphs"])
self.assertEqual(response["period_name"], period)
# custom period
today = datetime.date.today()
start = "{} 11:00:00".format(today)
end = "{} 11:40:00".format(today)
response = self.ajax_get(
"{}?gset=mailtraffic&period=custom&start={}&end={}".format(
url, start, end)
)
self.assertIn("averagetraffic", response["graphs"])
# unknown domain
response = self.ajax_get(
"{}?gset=mailtraffic&searchquery=unknown.com".format(url),
status=400)
# check with greylist enabled
self.set_global_parameter("greylist", True)
response = self.ajax_get("{}?gset=mailtraffic".format(url))
self.assertIn("averagetraffic", response["graphs"])
def test_account_created_graph(self):
"""Check data."""
self.run_update_statistics(rebuild=True)
url = reverse("maillog:graph_list")
response = self.ajax_get("{}?gset=accountgraphicset".format(url))
data = (
response["graphs"]["accountcreationgraphic"]["curves"][0]["data"])
self.assertEqual(data[-1]["y"], 5.0)
def test_graphs_as_domainadmin(self):
"""Test graph views as domain admin."""
self.run_logparser()
self.client.force_login(self.da)
url = "{}?gset=mailtraffic".format(reverse("maillog:graph_list"))
response = self.ajax_get(url)
self.assertIn("averagetraffic", response["graphs"])
response = self.ajax_get("{}&searchquery=test.com".format(url))
self.assertIn("averagetraffic", response["graphs"])
response = self.ajax_get(
"{}&searchquery=test2.com".format(url), status=403)
def test_get_domain_list(self):
"""Test get_domain_list view."""
url = reverse("maillog:domain_list")
response = self.ajax_get(url)
self.assertIn("test.com", response)
self.assertIn("test2.com", response)
@override_settings(RRDTOOL_TEST_MODE=True)
class ManagementCommandsTestCase(RunCommandsMixin, ModoTestCase):
"""Management command test cases."""
@classmethod
def setUpTestData(cls): # noqa
super(ManagementCommandsTestCase, cls).setUpTestData()
admin_factories.populate_database()
def test_logparser(self):
"""Test logparser command."""
self.run_logparser()
for d in ["global", "test.com"]:
path = os.path.join(self.workdir, "{}.rrd".format(d))
self.assertTrue(os.path.exists(path))
def test_logparser_with_greylist(self):
"""Test logparser when greylist activated."""
self.set_global_parameter("greylist", True)
self.run_logparser()
for d in ["global", "test.com"]:
path = os.path.join(self.workdir, "{}.rrd".format(d))
self.assertTrue(os.path.exists(path))
def test_update_statistics(self):
"""Test update_statistics command."""
self.run_update_statistics()
path = os.path.join(self.workdir, "new_accounts.rrd")
self.assertTrue(os.path.exists(path))
self.run_update_statistics(rebuild=True)
self.assertTrue(os.path.exists(path))
+13
View File
@@ -0,0 +1,13 @@
"""Stats urls."""
from django.urls import path
from . import views
app_name = "maillog"
urlpatterns = [
path("", views.index, name="fullindex"),
path("graphs/", views.graphs, name="graph_list"),
path("domains/", views.get_domain_list, name="domain_list"),
]
+103
View File
@@ -0,0 +1,103 @@
# coding: utf-8
"""Custom views."""
import re
import time
from django.shortcuts import render
from django.utils.translation import ugettext as _
from django.contrib.auth.decorators import (
login_required, user_passes_test, permission_required
)
from modoboa.admin.models import Domain
from modoboa.lib.exceptions import BadRequest, NotFound
from modoboa.lib.web_utils import (
render_to_json_response
)
from . import signals
from .lib import date_to_timestamp
@login_required
@permission_required("admin.view_mailbox")
def index(request):
"""
FIXME: how to select a default graph set ?
"""
deflocation = "graphs/?gset=mailtraffic"
if not request.user.is_superuser:
if not Domain.objects.get_for_admin(request.user).count():
raise NotFound(_("No statistics available"))
graph_sets = {}
for result in signals.get_graph_sets.send(
sender="index", user=request.user):
graph_sets.update(result[1])
periods = [
{"name": "day", "label": _("Day")},
{"name": "week", "label": _("Week")},
{"name": "month", "label": _("Month")},
{"name": "year", "label": _("Year")},
{"name": "custom", "label": _("Custom")}
]
return render(request, 'maillog/index.html', {
"periods": periods,
"selection": "stats",
"deflocation": deflocation,
"graph_sets": graph_sets
})
@login_required
@user_passes_test(lambda u: u.role != "SimpleUsers")
def graphs(request):
gset = request.GET.get("gset", None)
graph_sets = {}
for result in signals.get_graph_sets.send(
sender="index", user=request.user):
graph_sets.update(result[1])
if gset not in graph_sets:
raise NotFound(_("Unknown graphic set"))
period = request.GET.get("period", "day")
tplvars = {"graphs": {}, "period": period}
fname = graph_sets[gset].get_file_name(request)
if fname is None:
raise BadRequest(_("Unknown domain"))
tplvars["fname"] = fname
if period == "custom":
if "start" not in request.GET or "end" not in request.GET:
raise BadRequest(_("Bad custom period"))
start = request.GET["start"]
end = request.GET["end"]
expr = re.compile(r'[:\- ]')
period_name = "%s_%s" % (expr.sub('', start), expr.sub('', end))
start = date_to_timestamp(expr.split(start))
end = date_to_timestamp(expr.split(end))
else:
end = int(time.mktime(time.localtime()))
start = "-1%s" % period
period_name = period
tplvars["domain_selector"] = graph_sets[gset].domain_selector
tplvars["graphs"] = graph_sets[gset].export(tplvars["fname"], start, end)
tplvars["period_name"] = period_name
tplvars["start"] = start
tplvars["end"] = end
return render_to_json_response(tplvars)
@login_required
@user_passes_test(lambda u: u.role != "SimpleUsers")
def get_domain_list(request):
"""Get the list of domains the user can see."""
doms = []
for dom in Domain.objects.get_for_admin(request.user):
doms += [dom.name]
doms += [alias.name for alias in dom.domainalias_set.all()]
return render_to_json_response(doms)
+1
View File
@@ -27,6 +27,7 @@ urlpatterns = [
path('', include("modoboa.core.urls")),
path('admin/', include("modoboa.admin.urls")),
path('dnstools/', include("modoboa.dnstools.urls")),
path('stats/', include("modoboa.maillog.urls")),
path('user/forward/', user_views.forward, name="user_forward"),
+1
View File
@@ -28,6 +28,7 @@ chardet
ovh
oath
redis
rrdtool>=0.1.11
aiosmtplib
aioredis
+1
View File
@@ -79,6 +79,7 @@ MODOBOA_APPS = (
'modoboa.parameters',
'modoboa.dnstools',
'modoboa.policyd',
'modoboa.maillog',
# Modoboa extensions here.
)