Index: /trunk/trac-hacks/announcerplugin/announcerplugin/api.py
===================================================================
--- /trunk/trac-hacks/announcerplugin/announcerplugin/api.py	(revision 450)
+++ /trunk/trac-hacks/announcerplugin/announcerplugin/api.py	(revision 745)
@@ -313,4 +313,5 @@
                     self.log.debug(stmt)
                     cursor.execute(stmt)
+                    db.commit()
 
         except Exception, e:
Index: /trunk/trac-hacks/announcerplugin/announcerplugin/htdocs/css/announcer_prefs.css
===================================================================
--- /trunk/trac-hacks/announcerplugin/announcerplugin/htdocs/css/announcer_prefs.css	(revision 596)
+++ /trunk/trac-hacks/announcerplugin/announcerplugin/htdocs/css/announcer_prefs.css	(revision 745)
@@ -6,8 +6,4 @@
     text-align: left;
     margin: 1em;
-}
-
-div.announcer_preference_box ul { 
-	list-style:none; 
 }
 
Index: /trunk/trac-hacks/announcerplugin/announcerplugin/formatters/ticket_email.py
===================================================================
--- /trunk/trac-hacks/announcerplugin/announcerplugin/formatters/ticket_email.py	(revision 175)
+++ /trunk/trac-hacks/announcerplugin/announcerplugin/formatters/ticket_email.py	(revision 745)
@@ -93,6 +93,8 @@
         long_changes = {}
         
-        for field, old_value in event.changes.items():
-            new_value = ticket[field]
+        changed_items = [(field, unicode(old_value)) for field, old_value in 
+            event.changes.items()]
+        for field, old_value in changed_items:
+            new_value = unicode(ticket[field])
             if ('\n' in new_value) or ('\n' in old_value):
                 # long_changes[field.capitalize()] = \
@@ -122,5 +124,5 @@
             project_name = self.env.project_name,
             project_desc = self.env.project_description,
-            project_link = self.env.project_url,
+            project_link = self.env.project_url or self.env.abs_href(),
             has_changes = short_changes or long_changes,
             long_changes = long_changes,
@@ -179,5 +181,5 @@
             project_name = self.env.project_name,
             project_desc = self.env.project_description,
-            project_link = self.env.project_url,
+            project_link = self.env.project_url or self.env.abs_href(),
             has_changes = short_changes or long_changes,
             long_changes = long_changes,
Index: /trunk/trac-hacks/announcerplugin/announcerplugin/subscribers/watchers.py
===================================================================
--- /trunk/trac-hacks/announcerplugin/announcerplugin/subscribers/watchers.py	(revision 732)
+++ /trunk/trac-hacks/announcerplugin/announcerplugin/subscribers/watchers.py	(revision 745)
@@ -77,5 +77,5 @@
                AND category=%s
                AND rule=%s
-        """, (sid, int(authenticated), 'watcher', realm, '*', resource))
+        """, (sid, int(authenticated), 'watcher', realm, '*', unicode(resource)))
         
         result = cursor.fetchone()
@@ -127,5 +127,5 @@
                AND category=%s
                AND rule=%s
-        """, (sid, int(authenticated), 'watcher', realm, '*', resource))
+        """, (sid, int(authenticated), 'watcher', realm, '*', unicode(resource)))
         
         if not use_db:
@@ -198,5 +198,5 @@
                AND realm=%s
                AND rule=%s
-        """, ('watcher', 'wiki', page.name))
+        """, ('watcher', 'wiki', unicode(page.name)))
 
         db.commit()
@@ -224,5 +224,5 @@
                AND realm=%s
                AND rule=%s
-        """, ('watcher', 'ticket', str(ticket.id)))
+        """, ('watcher', 'ticket', unicode(ticket.id)))
 
         db.commit()
@@ -250,5 +250,5 @@
                        AND rule=%s
                 """, ('watcher', event.realm, '*', 
-                    str(self._get_target_identifier(event.realm, 
+                    unicode(self._get_target_identifier(event.realm, 
                     event.target))))
             
Index: /trunk/trac-hacks/announcerplugin/announcerplugin/subscribers/ticket_compat.py
===================================================================
--- /trunk/trac-hacks/announcerplugin/announcerplugin/subscribers/ticket_compat.py	(revision 559)
+++ /trunk/trac-hacks/announcerplugin/announcerplugin/subscribers/ticket_compat.py	(revision 745)
@@ -49,7 +49,12 @@
         notification section, except users can opt-out in their preferences. Used
         only if LegacyTicketSubscriber is enabled.""")
+
+    always_notify_component_owner = BoolOption("announcer", 
+            "always_notify_component_owner", True,
+            """Whether or not to notify the owner of the ticket's 
+            component.""")
         
     def get_announcement_preference_boxes(self, req):
-        yield "legacy", "Legacy Notification (Opt-Out)"
+        yield "legacy", "Ticket Notifications"
 
     def render_announcement_preference_box(self, req, panel):
@@ -69,9 +74,9 @@
         if req.method == "POST":
             if always_notify_owner:
-                sess['announcer_legacy_notify_owner'] = req.args.get('legacy_notify_owner', False)
+                sess['announcer_legacy_notify_owner'] = unicode(req.args.get('legacy_notify_owner', False))
             if always_notify_reporter:
-                sess['announcer_legacy_notify_reporter'] = req.args.get('legacy_notify_reporter', False)
+                sess['announcer_legacy_notify_reporter'] = unicode(req.args.get('legacy_notify_reporter', False))
             if always_notify_updater:
-                sess['announcer_legacy_notify_updater'] = req.args.get('legacy_notify_updater', False)
+                sess['announcer_legacy_notify_updater'] = unicode(req.args.get('legacy_notify_updater', False))
         
         data = dict(
@@ -100,13 +105,13 @@
             
             if event.category in ('created', 'changed', 'attachment added'):
-                try:
-                    # this throws an exception if the component does not exist
-                    component = model.Component(self.env, ticket['component'])
-                    if component.owner:
-                        ## TODO: Is this an option?
-                        self.log.debug("LegacyTicketSubscriber added '%s' because of rule: component owner" % (component.owner,))
-                        yield ('email', component.owner, True, None)
-                except ResourceNotFound, message:
-                    self.log.warn("LegacyTicketSubscriber couldn't add component owner because component was not found, message: '%s'" % (message,))    
+                if self.always_notify_component_owner:
+                    try:
+                        # this throws an exception if the component does not exist
+                        component = model.Component(self.env, ticket['component'])
+                        if component.owner:
+                            self.log.debug("LegacyTicketSubscriber added '%s' because of rule: component owner" % (component.owner,))
+                            yield ('email', component.owner, True, None)
+                    except ResourceNotFound, message:
+                        self.log.warn("LegacyTicketSubscriber couldn't add component owner because component was not found, message: '%s'" % (message,))    
 
                 if self.always_notify_owner and ticket['owner'] and not self._check_opt_out('notify_owner', ticket['owner']):                   
Index: /trunk/trac-hacks/announcerplugin/announcerplugin/distributors/email_distributor.py
===================================================================
--- /trunk/trac-hacks/announcerplugin/announcerplugin/distributors/email_distributor.py	(revision 631)
+++ /trunk/trac-hacks/announcerplugin/announcerplugin/distributors/email_distributor.py	(revision 745)
@@ -3,4 +3,6 @@
 from trac.config import Option, BoolOption, IntOption, OrderedExtensionsOption
 from trac.util import get_pkginfo
+from trac.util.translation import _
+
 from announcerplugin.api import IAnnouncementDistributor
 from announcerplugin.api import IAnnouncementFormatter
@@ -13,5 +15,8 @@
 from email.MIMEText import MIMEText
 from email.Utils import formatdate
-from email.header import Header
+try:
+    from email.header import Header
+except:
+    from email.Header import Header
 import time, Queue, threading, smtplib
 
@@ -119,10 +124,15 @@
     
     default_email_format = Option('announcer', 'default_email_format', 'text/plain')
-    
+
     def __init__(self):
-        if self.smtp_enabled and self.use_threaded_delivery:
-            self._deliveryQueue = Queue.Queue()
-            thread = DeliveryThread(self._deliveryQueue, self._transmit)
+        self.delivery_queue = None
+
+    def get_delivery_queue(self):
+        if not self.delivery_queue:
+            self.delivery_queue = Queue.Queue()
+            thread = DeliveryThread(self.delivery_queue, self._transmit)
             thread.start()
+
+        return self.delivery_queue
     
     # IAnnouncementDistributor
@@ -133,5 +143,4 @@
         if not self.smtp_enabled:
             return
-        
         public_cc = self.config.getbool('announcer', 'use_public_cc')
         to = self.config.get('announcer', 'smtp_to')
@@ -228,5 +237,5 @@
         subject = formatter.format_subject(transport, event.realm, format, event)
         
-        charset = self.env.config.get('trac', 'default_charset') or 'utf-8'
+        charset = self.env.config.get('trac', 'default_charset', 'utf-8')
         alternate_format = formatter.get_format_alternative(transport, event.realm, format)
         if alternate_format:
@@ -277,5 +286,5 @@
         package = (self.smtp_from, [x[2] for x in recipients if x], rootMessage.as_string() )
         if self.use_threaded_delivery:
-            self._deliveryQueue.put(package)
+            self.get_delivery_queue().put(package)
         else:
             self._transmit(*package)
@@ -285,8 +294,10 @@
 
     def _transmit(self, smtpfrom, addresses, message):
-        smtp = smtplib.SMTP()
-        smtp.connect(self.smtp_server)
+        smtp = smtplib.SMTP(self.smtp_server, self.smtp_port)
         if self.use_tls:
             smtp.ehlo()
+            if not smtp.esmtp_features.has_key('starttls'):
+                raise TracError(_("TLS enabled but server does not support " \
+                        "TLS"))
             smtp.starttls()
             smtp.ehlo()
Index: /trunk/trac-hacks/announcerplugin/announcerplugin/templates/prefs_announcer_joinable_groups.html
===================================================================
--- /trunk/trac-hacks/announcerplugin/announcerplugin/templates/prefs_announcer_joinable_groups.html	(revision 175)
+++ /trunk/trac-hacks/announcerplugin/announcerplugin/templates/prefs_announcer_joinable_groups.html	(revision 745)
@@ -5,8 +5,8 @@
   receive any email for them unless you choose to. They are general topics that may be added onto the CC list of tickets
   (by prepending their name with @), which can be used to bring specific attention to those people who are concerned
-  with the topic.
+  with the topic. Case does matter.
   <ul py:for="group in joinable_groups">
     <li>
-      <input type="checkbox" name="joinable_group_${group}" checked="${joinable_groups[group]}" value="1" /> ${group.capitalize()}
+      <input type="checkbox" name="joinable_group_${group}" checked="${joinable_groups[group]}" value="1" /> ${group}
     </li>
   </ul>
Index: /trunk/trac-hacks/announcerplugin/announcerplugin/templates/prefs_announcer_legacy.html
===================================================================
--- /trunk/trac-hacks/announcerplugin/announcerplugin/templates/prefs_announcer_legacy.html	(revision 175)
+++ /trunk/trac-hacks/announcerplugin/announcerplugin/templates/prefs_announcer_legacy.html	(revision 745)
@@ -2,19 +2,17 @@
      xmlns:py="http://genshi.edgewall.org/"
      xmlns:xi="http://www.w3.org/2001/XInclude">
-  The legacy mode has been activated by the administrators, with the following options:
   <ul>
     <li py:if="always_notify_owner">
       <input type="checkbox" name="legacy_notify_owner" checked="${legacy_notify_owner}" value="1" />
-      Always notify the ticket's owner.
+      Notify me of changes to tickets that I own.
     </li>        
     <li py:if="always_notify_reporter">
       <input type="checkbox" name="legacy_notify_reporter" checked="${legacy_notify_reporter}" value="1" />
-      Always notify the ticket's reporter.
+      Notify me of changes to tickets that I reported.
     </li>        
     <li py:if="always_notify_updater">
       <input type="checkbox" name="legacy_notify_updater" checked="${legacy_notify_updater}" value="1" />
-      Always notify the person updating the ticket.
+      Notify me when I update a ticket.
     </li>        
   </ul>
-  If you would like to opt-out of any of these announcements, simply uncheck them.
 </span>
