diff --git a/CHANGES.rst b/CHANGES.rst
index 570eeab..86e2a22 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -4,10 +4,21 @@ Changelog
 3.0b5 (unreleased)
 ------------------
 
+- Fix regression with exception handling in ``<dtml-except>`` with Python 2.
+  (`#25 <https://github.com/zopefoundation/DocumentTemplate/issues/25>`_)
+
 - Stabilized TreeTag rendering for objects without ``_p_oid`` values.
+  (`#26 <https://github.com/zopefoundation/DocumentTemplate/issues/26>`_)
 
 - Added support for Python 3.7.
 
+- Remove support for string exceptions in ``<dtml-except>``.
+  (`#29 <https://github.com/zopefoundation/DocumentTemplate/pull/29>`_)
+
+- Fix handling of parsing ``ParseError``s in Python 3.
+  (`#29 <https://github.com/zopefoundation/DocumentTemplate/pull/29>`_)
+
+
 3.0b4 (2018-07-12)
 ------------------
 
diff --git a/src/DocumentTemplate/DT_String.py b/src/DocumentTemplate/DT_String.py
index 1b0589d..2a0a783 100644
--- a/src/DocumentTemplate/DT_String.py
+++ b/src/DocumentTemplate/DT_String.py
@@ -175,7 +175,7 @@ class String(object):
             try:
                 tag, args, command, coname = self._parseTag(mo)
             except ParseError as m:
-                self.parse_error(m[0], m[1], text, l_)
+                self.parse_error(m.args[0], m.args[1], text, l_)
 
             s = text[start:l_]
             if s:
@@ -195,7 +195,7 @@ class String(object):
                         r = r.simple_form
                     result.append(r)
                 except ParseError as m:
-                    self.parse_error(m[0], tag, text, l_)
+                    self.parse_error(m.args[0], tag, text, l_)
 
             mo = tagre.search(text, start)
 
@@ -234,7 +234,7 @@ class String(object):
             try:
                 tag, args, command, coname = self._parseTag(mo, scommand, sa)
             except ParseError as m:
-                self.parse_error(m[0], m[1], text, l_)
+                self.parse_error(m.args[0], m.args[1], text, l_)
 
             if command:
                 start = l_ + len(tag)
@@ -264,7 +264,7 @@ class String(object):
                             r = r.simple_form
                         result.append(r)
                     except ParseError as m:
-                        self.parse_error(m[0], stag, text, l_)
+                        self.parse_error(m.args[0], stag, text, l_)
 
                     return start
 
@@ -279,7 +279,7 @@ class String(object):
             try:
                 tag, args, command, coname = self._parseTag(mo, scommand, sa)
             except ParseError as m:
-                self.parse_error(m[0], m[1], text, l_)
+                self.parse_error(m.args[0], m.args[1], text, l_)
 
             start = l_ + len(tag)
             if command:
diff --git a/src/DocumentTemplate/DT_Try.py b/src/DocumentTemplate/DT_Try.py
index 3a2bfbd..972eb56 100644
--- a/src/DocumentTemplate/DT_Try.py
+++ b/src/DocumentTemplate/DT_Try.py
@@ -14,7 +14,7 @@
 import sys
 import traceback
 
-from io import StringIO
+from six import StringIO
 from DocumentTemplate.DT_Util import ParseError, parse_params, render_blocks
 from DocumentTemplate.DT_Util import namespace, InstanceDict
 from DocumentTemplate.DT_Return import DTReturn
@@ -154,10 +154,7 @@ class Try(object):
         except Exception:
             # but an error occurs.. save the info.
             t, v = sys.exc_info()[:2]
-            if isinstance(t, str):
-                errname = t
-            else:
-                errname = t.__name__
+            errname = t.__name__
 
             handler = self.find_handler(t)
 
@@ -196,12 +193,6 @@ class Try(object):
 
     def find_handler(self, exception):
         "recursively search for a handler for a given exception"
-        if isinstance(exception, str):
-            for e, h in self.handlers:
-                if exception == e or e == '':
-                    return h
-            else:
-                return None
         for e, h in self.handlers:
             if (e == exception.__name__ or
                     e == '' or self.match_base(exception, e)):
diff --git a/tox.ini b/tox.ini
index 573cf02..d3f6891 100644
--- a/tox.ini
+++ b/tox.ini
@@ -30,7 +30,7 @@ commands =
     coverage combine
     coverage html
     coverage xml
-    coverage report --fail-under=67
+    coverage report --fail-under=71
 
 [testenv:flake8]
 basepython = python3.6

diff --git a/src/DocumentTemplate/tests/test_DT_Try.py b/src/DocumentTemplate/tests/test_DT_Try.py
new file mode 100644
index 0000000..8f5950d
--- /dev/null
+++ b/src/DocumentTemplate/tests/test_DT_Try.py
@@ -0,0 +1,230 @@
+import unittest
+
+from DocumentTemplate.DT_Util import ParseError
+from DocumentTemplate.DT_Raise import InvalidErrorTypeExpression
+
+
+class DT_Try_Tests(unittest.TestCase):
+    """Testing ..DT_Try.Try."""
+
+    def _get_doc_class(self):
+        from DocumentTemplate.DT_HTML import HTML
+        return HTML
+
+    doc_class = property(_get_doc_class,)
+
+    def test_DT_Try__Try____init__1(self):
+        """It allows only one else block."""
+        html = self.doc_class(
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-except>'
+            '<dtml-else>'
+            '<dtml-var expr="str(100)">'
+            '<dtml-else>'
+            '<dtml-var expr="str(110)">'
+            '</dtml-try>')
+        with self.assertRaisesRegexp(ParseError, '^No more than one else '):
+                html()
+
+    def test_DT_Try__Try____init__2(self):
+        """It allows the else block only in last position."""
+        html = self.doc_class(
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-else>'
+            '<dtml-var expr="str(100)">'
+            '<dtml-except>'
+            '</dtml-try>')
+        with self.assertRaisesRegexp(
+                ParseError, '^The else block should be the last '):
+            html()
+
+    def test_DT_Try__Try____init__3(self):
+        """It allows no except block with a finally block."""
+        html = self.doc_class(
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-except>'
+            '<dtml-finally>'
+            '<dtml-var expr="str(100)">'
+            '</dtml-try>')
+        with self.assertRaisesRegexp(
+                ParseError, '^A try..finally combination cannot '):
+            html()
+
+    def test_DT_Try__Try____init__4(self):
+        """It allows only one default exception handler."""
+        html = self.doc_class(
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-except>'
+            '<dtml-var expr="str(100)">'
+            '<dtml-except>'
+            '<dtml-var expr="str(110)">'
+            '</dtml-try>')
+        with self.assertRaisesRegexp(
+                ParseError, '^Only one default exception handler '):
+            html()
+
+    def test_DT_Try__Try__01(self):
+        """It renders a try block if no exception occurs."""
+        html = self.doc_class(
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-var expr="str(100)">'
+            '</dtml-try>')
+        res = html()
+        expected = 'Variable "name": 100'
+        self.assertEqual(res, expected)
+
+    def test_DT_Try__Try__02(self):
+        """It renders the except block if an exception occurs."""
+        html = self.doc_class(
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-var expr="not_defined">'
+            '<dtml-except>'
+            'Exception variable: '
+            '<dtml-var expr="str(100)">'
+            '</dtml-try>')
+        res = html()
+        expected = 'Exception variable: 100'
+        self.assertEqual(res, expected)
+
+    def test_DT_Try__Try__03(self):
+        """It renders the else block if no exception occurs."""
+        html = self.doc_class(
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-var expr="str(100)"> '
+            '<dtml-except>'
+            'Exception variable: '
+            '<dtml-var expr="str(110)"> '
+            '<dtml-else>'
+            'Else variable: '
+            '<dtml-var expr="str(111)"> '
+            '</dtml-try>')
+        res = html()
+        expected = ('Variable "name": 100 '
+                    'Else variable: 111 ')
+        self.assertEqual(res, expected)
+
+    def test_DT_Try__Try__04(self):
+        """It executes the finally block if no exception occurs."""
+        html = self.doc_class(
+            '<dtml-call expr="dummy_list.append(110)">'
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-var expr="str(100)"> '
+            '<dtml-finally>'
+            'Finally variable: '
+            '<dtml-var expr="str(111)"> '
+            '<dtml-call expr="dummy_list.pop(0)">'
+            '</dtml-try>')
+        dummy_list = [100]
+
+        res = html(dummy_list=dummy_list)
+        expected = ('Variable "name": 100 '
+                    'Finally variable: 111 ')
+        self.assertEqual(res, expected)
+        # 100 got removed in the finally block.
+        self.assertEqual(dummy_list, [110])
+
+    def test_DT_Try__Try__05(self):
+        """It executes the finally block if an exception occurs."""
+        html = self.doc_class(
+            '<dtml-call expr="dummy_list.append(110)">'
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-var expr="not_defined"> '
+            '<dtml-finally>'
+            'Finally variable: '
+            '<dtml-call expr="dummy_list.pop(0)"> '
+            '</dtml-try>')
+        dummy_list = [100]
+
+        with self.assertRaises(NameError):
+            html(dummy_list=dummy_list)
+        # 100 got removed in the finally block.
+        self.assertEqual(dummy_list, [110])
+
+    def test_DT_Try__Try__06(self):
+        """It allows different exception handlers."""
+        html = self.doc_class(
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-var expr="not_defined">'
+            '<dtml-except KeyError>'
+            'Exception variable: '
+            '<dtml-var expr="str(100)">'
+            '<dtml-except NameError>'
+            'Exception variable: '
+            '<dtml-var expr="str(110)">'
+            '</dtml-try>')
+        res = html()
+        expected = 'Exception variable: 110'
+        self.assertEqual(res, expected)
+
+    def test_DT_Try__Try__07(self):
+        """It catches errors with handler for base exception."""
+        html = self.doc_class(
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-raise KeyError></dtml-raise>'
+            '<dtml-except NameError>'
+            'Exception variable: '
+            '<dtml-var expr="str(100)">'
+            '<dtml-except LookupError>'
+            'Exception variable: '
+            '<dtml-var expr="str(110)">'
+            '</dtml-try>')
+        res = html()
+        expected = 'Exception variable: 110'
+        self.assertEqual(res, expected)
+
+    def test_DT_Try__Try__08(self):
+        """It raises the occurred exception if no exception handler matches."""
+        html = self.doc_class(
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-var expr="not_defined">'
+            '<dtml-except KeyError>'
+            'Exception variable: '
+            '<dtml-var expr="str(100)">'
+            '<dtml-except AttributeError>'
+            'Exception variable: '
+            '<dtml-var expr="str(110)">'
+            '</dtml-try>')
+        with self.assertRaises(NameError):
+                html()
+
+    def test_DT_Try__Try__09(self):
+        """It returns a dtml-return immediately."""
+        html = self.doc_class(
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-return ret>'
+            '<dtml-raise KeyError></dtml-raise>'
+            '<dtml-except LookupError>'
+            'Exception variable: '
+            '<dtml-var expr="str(110)">'
+            '</dtml-try>')
+        res = html(ret='Return variable: 101')
+        expected = 'Return variable: 101'
+        self.assertEqual(res, expected)
+
+    def test_DT_Try__Try__10(self):
+        """It does not break with strings as exceptions but raises a well
+
+        defined exception in that case."""
+        html = self.doc_class(
+            '<dtml-try>'
+            'Variable "name": '
+            '<dtml-raise "FakeError"></dtml-raise>'
+            '<dtml-except NameError>'
+            'Exception variable: '
+            '<dtml-var expr="str(110)">'
+            '</dtml-try>')
+        with self.assertRaises(InvalidErrorTypeExpression):
+                html()

<dtml-except> breaks on Python 2
Traceback:
```python
src/Zope/src/App/special_dtml.py:203: in _exec
    result = render_blocks(self._v_blocks, ns)
.../DocumentTemplate-3.0b4-py2.7.egg/DocumentTemplate/_DocumentTemplate.py:148: in render_blocks
    render_blocks_(blocks, rendered, md)
.../DocumentTemplate-3.0b4-py2.7.egg/DocumentTemplate/_DocumentTemplate.py:249: in render_blocks_
    block = block(md)
.../DocumentTemplate-3.0b4-py2.7.egg/DocumentTemplate/DT_Try.py:142: in render
    return self.render_try_except(md)
.../DocumentTemplate-3.0b4-py2.7.egg/DocumentTemplate/DT_Try.py:171: in render_try_except
    traceback.print_exc(100, f)
/usr/lib64/python2.7/traceback.py:233: in print_exc
    print_exception(etype, value, tb, limit, file)
/usr/lib64/python2.7/traceback.py:124: in print_exception
    _print(file, 'Traceback (most recent call last):')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

file = <_io.StringIO object at 0x7f8ef106e150>, str = 'Traceback (most recent call last):', terminator = '\n'

    def _print(file, str='', terminator='\n'):
>       file.write(str+terminator)
E       TypeError: unicode argument expected, got 'str'
```

Reason: The used `io.StringIO` in `DT_Try.py` expects `unicode` to be written to it, but `traceback.py` from standard lib insists to write `str`.

Possible solution: Use `cStringIO.StringIO` as it was before version 3.0a3 but only on Python 2.
src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try____init__1 src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try____init__2 src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try____init__3 src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try____init__4
src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try__01 src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try__02 src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try__03 src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try__04 src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try__05 src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try__06 src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try__07 src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try__08 src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try__09 src/DocumentTemplate/tests/test_DT_Try.py::DT_Try_Tests::test_DT_Try__Try__10