diff --git a/trac/ticket/notification.py b/trac/ticket/notification.py
index df67904..ab5e343 100644
--- a/trac/ticket/notification.py
+++ b/trac/ticket/notification.py
@@ -22,10 +22,11 @@ from trac.notification import NotifyEmail
 from trac.ticket.api import TicketSystem
 from trac.util import md5
 from trac.util.datefmt import to_utimestamp
-from trac.util.text import CRLF, wrap, obfuscate_email_address
+from trac.util.text import CRLF, wrap, obfuscate_email_address, to_unicode
 from trac.util.translation import deactivate, reactivate
 
 from genshi.template.text import NewTextTemplate
+from unicodedata import east_asian_width
 
 class TicketNotificationSystem(Component):
 
@@ -51,6 +52,14 @@ class TicketNotificationSystem(Component):
         `$prefix` being the value of the `smtp_subject_prefix` option.
         ''(since 0.11)''""")
 
+    ambiguous_char_width = Option('notification', 'ambiguous_char_width', 'single',
+        """Which width of ambiguous characters (e.g. 'single' or 'double')
+        should be used in the table of notification mail.
+
+        If 'single', the same width as characters in US-ASCII. This is expected
+        by most users. If 'double', twice the width of US-ASCII characters.
+        This is expected by CJK users.""")
+
 
 class TicketNotifyEmail(NotifyEmail):
     """Notification of ticket changes."""
@@ -65,6 +74,8 @@ class TicketNotifyEmail(NotifyEmail):
     def __init__(self, env):
         NotifyEmail.__init__(self, env)
         self.prev_cc = []
+        self.ambiguous_char_width = env.config.get('notification', 'ambiguous_char_width', 'single')
+        self.text_widths = {}
 
     def notify(self, ticket, newticket=True, modtime=None):
         """Send ticket change notification e-mail (untranslated)"""
@@ -180,13 +191,13 @@ class TicketNotifyEmail(NotifyEmail):
             if fval.find('\n') != -1:
                 continue
             idx = 2 * (i % 2)
-            if len(f) > width[idx]:
-                width[idx] = len(f)
-            if len(fval) > width[idx + 1]:
-                width[idx + 1] = len(fval)
+            text_width = self.get_text_width(f)
+            if text_width > width[idx]:
+                width[idx] = text_width
+            text_width = self.get_text_width(fval)
+            if text_width > width[idx + 1]:
+                width[idx + 1] = text_width
             i += 1
-        format = (u'%%%is:  %%-%is  |  ' % (width[0], width[1]),
-                  u' %%%is:  %%-%is%s' % (width[2], width[3], CRLF))
         l = (width[0] + width[1] + 5)
         sep = l * '-' + '+' + (self.COLS - l) * '-'
         txt = sep + CRLF
@@ -204,7 +215,17 @@ class TicketNotifyEmail(NotifyEmail):
             else:
                 # Note: f['label'] is a Babel's LazyObject, make sure its
                 # __str__ method won't be called.
-                txt += format[i % 2] % (f['label'], unicode(fval))
+                flabel = f['label']
+                if i % 2 == 0:
+                    format = u'%%%is:  %%-%is  |  ' % (
+                                width[0] - (self.get_text_width(flabel) - len(flabel)),
+                                width[1] - (self.get_text_width(fval) - len(fval)))
+                else:
+                    format = u' %%%is:  %%-%is%s' % (
+                                width[2] - (self.get_text_width(flabel) - len(flabel)),
+                                width[3] - (self.get_text_width(fval) - len(fval)),
+                                CRLF)
+                txt += format % (flabel, unicode(fval))
                 i += 1
         if i % 2:
             txt += CRLF
@@ -327,3 +348,27 @@ class TicketNotifyEmail(NotifyEmail):
             hdrs['References'] = msgid
         NotifyEmail.send(self, torcpts, ccrcpts, hdrs)
 
+    def get_text_width(self, text):
+        if self.ambiguous_char_width == 'double':
+            ambiwidth = 2
+        else:
+            ambiwidth = 1
+
+        if not isinstance(text, unicode):
+            text = to_unicode(text)
+
+        if text in self.text_widths:
+            return self.text_widths[text]
+
+        width = 0
+        for ch in text:
+            eaw = east_asian_width(ch)
+            if eaw == 'W' or eaw == 'F':
+                width += 2
+            elif eaw == 'A':
+                width += ambiwidth
+            else:
+                width += 1
+        self.text_widths[text] = width
+        return width
+

