Friday, May 13, 2016¶
Problems with sending email from a VPS¶
On both The Lino framework and mylino.net I have currently problems when sending emails from my Lino applications.
To explore these problems, I used the following sendmail.py
script:
from __future__ import print_function
from django.conf import settings
from django.core.mail import EmailMessage
for k in """EMAIL_HOST EMAIL_HOST_USER
DEFAULT_FROM_EMAIL SERVER_EMAIL EMAIL_PORT EMAIL_USE_TLS
""".split():
print("{0} : {1}".format(k, getattr(settings, k)))
email = EmailMessage('Subject', 'Body', to=['luc.saffre@gmx.net'])
email.send()
This script is to be invoked via pm run
as follows:
$ python manage.py run sendmail.py
On mylino.net (which is hosted in France at OVH), my first attempt takes about 1 minute to complete, and then I get:
EMAIL_HOST : mx3.ovh.net
EMAIL_HOST_USER :
DEFAULT_FROM_EMAIL : noreply@mylino.net
SERVER_EMAIL : noreply@mylino.net
EMAIL_PORT : 25
EMAIL_USE_TLS : True
...
Traceback (most recent call last):
...
smtplib.SMTPRecipientsRefused: {u'luc.saffre@gmx.net': (553, "sorry, that domain isn't allowed to be relayed thru this MTA [mail497] (#5.7.1)")}
According to this page their STMP server is ns0.ovh.net. When I try this, I get another error message:
smtplib.SMTPRecipientsRefused: {u'luc.saffre@gmx.net': (554, '5.7.1 <133.ip-167-114-252.eu[167.114.252.133]>: Client host rejected: Access denied')}
While on The Lino framework (hosted in Estonia by Elisa) I get another error:
EMAIL_HOST : smtp.elisa.ee
EMAIL_HOST_USER :
DEFAULT_FROM_EMAIL : noreply@lino-framework.org
SERVER_EMAIL : noreply@lino-framework.org
EMAIL_PORT : 25
EMAIL_USE_TLS : False
Traceback (most recent call last):
...
socket.gaierror: [Errno -2] Name or service not known
Adapting test suites¶
I adapted the test suites of Lino Così and Lino Welfare (#881).
As a side-effect, I changed the output format of the fab
summary
command to be shorter. On my machine it is now:
========= ========================================== ========= ========================
Project URL Version doctrees
--------- ------------------------------------------ --------- ------------------------
atelier http://atelier.lino-framework.org 1.0.0 docs
cd https://github.com/lsaffre/commondata 0.0.1 docs
be https://github.com/lsaffre/commondata-be 0.0.1
ee https://github.com/lsaffre/commondata-ee 0.0.1
lino http://www.lino-framework.org 1.7.0 docs
xl http://www.lino-framework.org 1.0.0 docs
noi http://noi.lino-framework.org 0.0.2 docs
cosi http://cosi.lino-framework.org 0.0.2 docs
welfare https://welfare.lino-framework.org 1.1.26 docs, docs_de, docs_fr
presto http://presto.lino-framework.org 0.0.1 docs
voga http://voga.lino-framework.org 0.0.4 docs
ext6 http://www.lino-framework.org 0.0.1 docs
patrols http://patrols.lino-framework.org 0.0.2 docs
logos http://logos.lino-framework.org 0.0.1 docs
dblog None docs
blog None docs
jsvv None docs
lucde None docs
lucet None docs
vv None docs
========= ========================================== ========= ========================
Generating invoices for a given course¶
I fixed #917. Until now, in Lino Voga it was a bit
complicated to generate invoices for a given course. Alexa had to
set the state of all other courses to Draft. This was of course
just a workaround. Now we have a good solution:
lino_voga.lib.invoicing
. This is an application-specific
extension of lino_xl.lib.invoicing
which, in short, adds a
new field course
to invoicing plans and a “basket” button to the Course model.
Side effect: When Lino generates invoices (by executing a plan), then these are now automatically registered.
A blocking bug¶
Alexa reported #918, her first blocking problem: a bug which made it impossible to create new enrolments (at least in courses whose max_places field was non-empty):
...
File "/cosi/lino_xl.lib.courses/models.py", line 510, in run_from_ui
msg = obj.get_confirm_veto(ar)
File "/cosi/lino_xl.lib.courses/models.py", line 609, in get_confirm_veto
free = self.course.get_free_places(self)
File "/cosi/lino_xl.lib.courses/models.py", line 366, in get_free_places
qs = PeriodEvents.active.add_filter(qs, rng)
File "/lino/lino/modlib/system/choicelists.py", line 87, in add_filter
Q(end_date__gte=obj.start_date))
File "/site-packages/django/db/models/query.py", line 790, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "/site-packages/django/db/models/query.py", line 808, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "/site-packages/django/db/models/sql/query.py", line 1243, in add_q
clause, _ = self._add_q(q_object, self.used_aliases)
File "/site-packages/django/db/models/sql/query.py", line 1263, in _add_q
current_negated, allow_joins, split_subq)
File "/site-packages/django/db/models/sql/query.py", line 1269, in _add_q
allow_joins=allow_joins, split_subq=split_subq,
File "/site-packages/django/db/models/sql/query.py", line 1203, in build_filter
condition = self.build_lookup(lookups, col, value)
File "/site-packages/django/db/models/sql/query.py", line 1099, in build_lookup
return final_lookup(lhs, rhs)
File "/site-packages/django/db/models/lookups.py", line 19, in __init__
self.rhs = self.get_prep_lookup()
File "/site-packages/django/db/models/lookups.py", line 57, in get_prep_lookup
return self.lhs.output_field.get_prep_lookup(self.lookup_name, self.rhs)
File "/site-packages/django/db/models/fields/__init__.py", line 744, in get_prep_lookup
return self.get_prep_value(value)
File "/site-packages/django/db/models/fields/__init__.py", line 1296, in get_prep_value
return self.to_python(value)
File "/site-packages/django/db/models/fields/__init__.py", line 1260, in to_python
parsed = parse_date(value)
File "/site-packages/django/utils/dateparse.py", line 60, in parse_date
match = date_re.match(value)
TypeError: expected string or buffer