diff --git a/Kernel/Config/Files/Ticket.xml b/Kernel/Config/Files/Ticket.xml
index 7793775..8b8dac8 100644
--- a/Kernel/Config/Files/Ticket.xml
+++ b/Kernel/Config/Files/Ticket.xml
@@ -8536,6 +8536,18 @@ $QData{"Signature"}
             </FrontendModuleReg>
         </Setting>
     </ConfigItem>
+    <ConfigItem Name="CustomerFrontend::Module###CustomerTicketWatcher" Required="0" Valid="1">
+        <Description Lang="en">Frontend module registration for the Customer Subscribe object in the customer interface.</Description>
+        <Group>Ticket</Group>
+        <SubGroup>Frontend::Customer::ModuleRegistration</SubGroup>
+        <Setting>
+            <FrontendModuleReg>
+                <Description>compat mod</Description>
+                <NavBarName></NavBarName>
+                <Title></Title>
+            </FrontendModuleReg>
+        </Setting>
+    </ConfigItem>
     <ConfigItem Name="CustomerFrontend::Module###CustomerTicketAttachment" Required="0" Valid="1">
         <Description Lang="en">Frontend module registration for the CustomerTicketAttachment object in the customer interface.</Description>
         <Description Lang="de">Frontendmodul-Registration des CustomerTicketAttachment-Objekts im Customer-Interface.</Description>
diff --git a/Kernel/Modules/CustomerTicketWatcher.pm b/Kernel/Modules/CustomerTicketWatcher.pm
new file mode 100644
index 0000000..456bac9
--- /dev/null
+++ b/Kernel/Modules/CustomerTicketWatcher.pm
@@ -0,0 +1,104 @@
+# --
+# Kernel/Modules/CustomerTicketWatcher.pm - a ticketwatcher module
+# Copyright (C) 2001-2009 OTRS AG, http://otrs.org/
+# Copyright (C) 2010 Atos Origin
+# --
+# $Id: AgentTicketWatcher.pm,v 1.11 2009/02/16 11:20:53 tr Exp $
+# --
+# This software comes with ABSOLUTELY NO WARRANTY. For details, see
+# the enclosed file COPYING for license information (AGPL). If you
+# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
+# --
+
+package Kernel::Modules::CustomerTicketWatcher;
+
+use strict;
+use warnings;
+
+use vars qw($VERSION);
+$VERSION = qw($Revision: 1.11 $) [1];
+
+sub new {
+    my ( $Type, %Param ) = @_;
+
+    # allocate new hash for object
+    my $Self = {%Param};
+    bless( $Self, $Type );
+
+    # check needed objects
+    for (qw(ParamObject DBObject LayoutObject LogObject ConfigObject)) {
+        if ( !$Self->{$_} ) {
+            $Self->{LayoutObject}->FatalError( Message => "Got no $_!" );
+        }
+    }
+
+    return $Self;
+}
+
+sub Run {
+    my ( $Self, %Param ) = @_;
+
+    # ------------------------------------------------------------ #
+    # check if feature is aktive
+    # ------------------------------------------------------------ #
+    if ( !$Self->{ConfigObject}->Get('Ticket::Watcher') ) {
+        return $Self->{LayoutObject}->ErrorScreen( Message => 'Feature is not aktive', );
+    }
+
+    # ------------------------------------------------------------ #
+    # check access
+    # ------------------------------------------------------------ #
+    my @Groups = ();
+    if ( $Self->{ConfigObject}->Get('Ticket::WatcherGroup') ) {
+        @Groups = @{ $Self->{ConfigObject}->Get('Ticket::WatcherGroup') };
+    }
+    my $Access = 0;
+    if ( !@Groups ) {
+        $Access = 1;
+    }
+    else {
+        for my $Group (@Groups) {
+            if ( $Self->{LayoutObject}->{"UserIsGroup[$Group]"} eq 'Yes' ) {
+                $Access = 1;
+            }
+        }
+    }
+
+    # ------------------------------------------------------------ #
+    # subscribe a ticket
+    # ------------------------------------------------------------ #
+    if ( $Self->{Subaction} eq 'Subscribe' ) {
+
+        # set subscribe
+        my $Subscribe = $Self->{TicketObject}->TicketCustomerWatchSubscribe(
+            TicketID    => $Self->{TicketID},
+            CustomerUserID => $Self->{UserID},
+        );
+
+        if ( !$Subscribe ) {
+            return $Self->{LayoutObject}->ErrorScreen();
+        }
+
+        # redirect
+        return $Self->{LayoutObject}->Redirect( OP => $Self->{LastScreenView} );
+    }
+
+    # ------------------------------------------------------------ #
+    # unsubscribe a ticket
+    # ------------------------------------------------------------ #
+    elsif ( $Self->{Subaction} eq 'Unsubscribe' ) {
+        my $Unsubscribe = $Self->{TicketObject}->TickeCustomertWatchUnsubscribe(
+            TicketID    => $Self->{TicketID},
+            CustomerUserID => $Self->{UserID},
+        );
+
+        if ( !$Unsubscribe ) {
+            return $Self->{LayoutObject}->ErrorScreen();
+        }
+
+        # redirect
+        return $Self->{LayoutObject}->Redirect( OP => $Self->{LastScreenView} );
+    }
+}
+
+1;
diff --git a/Kernel/Output/HTML/Standard/CustomerTicketZoom.dtl b/Kernel/Output/HTML/Standard/CustomerTicketZoom.dtl
index a0f9274..e7f3dd0 100644
--- a/Kernel/Output/HTML/Standard/CustomerTicketZoom.dtl
+++ b/Kernel/Output/HTML/Standard/CustomerTicketZoom.dtl
@@ -55,6 +55,8 @@ function submit_compose() {
     <tr>
         <td width="70%" class="menu">
             <a href="$Env{"Baselink"}Action=CustomerTicketPrint&TicketID=$QData{"TicketID"}" onmouseover="window.status='$JSText{"Print"}'; return true;" onmouseout="window.status='';" target="_blank">$Text{"Print"}</a>
+-
+            <a href="$Env{"Baselink"}Action=CustomerTicketWatcher&&Subaction=Subscribe&TicketID=$QData{"TicketID"}" onmouseover="window.status='$JSText{"Watch"}'; return true;" onmouseout="window.status='';" target="_blank">$Text{"Subscribe"}</a>
         </td>
         <td align="right" width="30%" class="menu">
             <b>$Text{"Created"}:</b> $TimeLong{"$Data{"Created"}"}
diff --git a/Kernel/System/Ticket.pm b/Kernel/System/Ticket.pm
index d2feaae..3082006 100644
--- a/Kernel/System/Ticket.pm
+++ b/Kernel/System/Ticket.pm
@@ -3237,6 +3237,60 @@ sub GetSubscribedUserIDsByQueueID {
     return @CleanUserIDs;
 }
 
+=item GetSubscribedCustomerIDsByQueueID()
+
+returns a array of user ids which selected the given queue id as
+custom queue.
+
+    my @UserIDs = $TicketObject->GetSubscribedUserIDsByQueueID(
+        QueueID => 123,
+    );
+
+=cut
+
+sub GetSubscribedCustomerIDsByQueueID {
+    my ( $Self, %Param ) = @_;
+
+    # check needed stuff
+    if ( !$Param{QueueID} ) {
+        $Self->{LogObject}->Log( Priority => 'error', Message => 'Need QueueID!' );
+        return;
+    }
+
+    # get group of queue
+    my %Queue = $Self->{QueueObject}->QueueGet( ID => $Param{QueueID} );
+
+    # fetch all queues
+    my @UserIDs = ();
+    return if !$Self->{DBObject}->Prepare(
+        SQL  => 'SELECT customer_user_id FROM personal_queues WHERE queue_id = ?',
+        Bind => [ \$Param{QueueID} ],
+    );
+    while ( my @Row = $Self->{DBObject}->FetchrowArray() ) {
+        push @UserIDs, $Row[0];
+    }
+
+    # check if user is valid and check permissions
+    my @CleanUserIDs = ();
+    for my $UserID (@UserIDs) {
+        my %User = $Self->{UserObject}->GetUserData( UserID => $UserID, Valid => 1 );
+        next if !%User;
+
+        # just send emails to permitted agents
+        my %GroupMember = $Self->{GroupObject}->GroupMemberList(
+            UserID => $UserID,
+            Type   => 'ro',
+            Result => 'HASH',
+        );
+        if ( $GroupMember{ $Queue{GroupID} } ) {
+            push @CleanUserIDs, $UserID;
+        }
+    }
+    return @CleanUserIDs;
+}
+
+
+
 =item TicketPendingTimeSet()
 
 set ticket pending time
@@ -6792,6 +6846,147 @@ sub TicketWatchUnsubscribe {
     return 1;
 }
 
+=item TicketCustomerWatchGet()
+
+get list of users as array
+
+    my Watch = $TicketObject->TicketWatchGet(
+        TicketID => 123,
+    );
+
+=cut
+
+sub TicketCustomerWatchGet {
+    my ( $Self, %Param ) = @_;
+
+    # check needed stuff
+    for (qw(TicketID)) {
+        if ( !$Param{$_} ) {
+            $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" );
+            return;
+        }
+    }
+
+    # check if feature is enabled
+    return if !$Self->{ConfigObject}->Get('Ticket::Watcher');
+
+    # get all attributes of an watched ticket
+    return if !$Self->{DBObject}->Prepare(
+        SQL => 'SELECT customer_user_id '
+            . ' FROM ticket_customer_watcher WHERE ticket_id = ?',
+        Bind => [ \$Param{TicketID} ],
+    );
+
+    # fetch the result
+    my %Data;
+    while ( my @Row = $Self->{DBObject}->FetchrowArray() ) {
+        $Data{ $Row[0] } = {
+            },
+    }
+
+    if ( $Param{Notify} ) {
+        for my $UserID ( keys %Data ) {
+            my %UserData = $Self->{UserObject}->GetUserData(
+                UserID => $UserID,
+                Cached => 1,
+                Valid  => 1,
+            );
+            if ( !$UserData{UserSendWatcherNotification} ) {
+                delete $Data{$UserID};
+            }
+        }
+    }
+
+    # check result
+    if ( $Param{Result} && $Param{Result} eq 'ARRAY' ) {
+        my @UserIDs;
+        for my $UserID ( keys %Data ) {
+            push @UserIDs, $UserID;
+        }
+        return @UserIDs;
+    }
+
+    return %Data;
+}
+
+
+
+=item TicketCustomerWatchSubscribe()
+
+for a customer to subscribe a ticket to watch it
+
+    $TicketObject->TicketWatchSubscribe(
+        TicketID    => 111,
+        CustomerUserID => 123,
+    );
+
+=cut
+
+sub TicketCustomerWatchSubscribe {
+    my ( $Self, %Param ) = @_;
+
+    # check needed stuff
+    for (qw(TicketID CustomerUserID)) {
+        if ( !defined $Param{$_} ) {
+            $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" );
+            return;
+        }
+    }
+
+    # db access
+    return if !$Self->{DBObject}->Do(
+        SQL => 'DELETE FROM ticket_customer_watcher WHERE ticket_id = ? AND
+        customer_user_id = ?',
+        Bind => [ \$Param{TicketID}, \$Param{CustomerUserID} ],
+    );
+    return if !$Self->{DBObject}->Do(
+        SQL =>
+            'INSERT INTO ticket_customer_watcher (ticket_id, customer_user_id, create_time) '
+            . ' VALUES (?, ?, current_timestamp)',
+        Bind => [ \$Param{TicketID}, \$Param{CustomerUserID} ],
+    );
+
+    # get user data
+    my %User = $Self->{UserObject}->GetUserData(
+        UserID => $Param{WatchUserID},
+        Cached => 1,
+    );
+
+    return 1;
+}
+
+=item TicketCustomerWatchUnsubscribe()
+
+to remove a customer subscribtion of a ticket
+
+    $TicketObject->TicketCustomerWatchUnsubscribe(
+        TicketID    => 111,
+        CustomerUserID      => 123,
+    );
+
+=cut
+
+sub TicketCustomerWatchUnsubscribe {
+    my ( $Self, %Param ) = @_;
+
+    # check needed stuff
+    for (qw(TicketID WatchUserID UserID)) {
+        if ( !defined $Param{$_} ) {
+            $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" );
+            return;
+        }
+    }
+
+    # db access
+    return if !$Self->{DBObject}->Do(
+        SQL => 'DELETE FROM ticket_customer_watcher WHERE ticket_id = ? AND user_id = ?',
+        Bind => [ \$Param{TicketID}, \$Param{CustomerUserID} ],
+    );
+
+
+    return 1;
+}
+
 =item TicketAcl()
 
 prepare ACL execution of current state
diff --git a/Kernel/System/Ticket/Article.pm b/Kernel/System/Ticket/Article.pm
index 4d2135e..7d34b73 100644
--- a/Kernel/System/Ticket/Article.pm
+++ b/Kernel/System/Ticket/Article.pm
@@ -596,6 +596,18 @@ sub ArticleCreate {
                     );
                 }
             }
+
+            my %customer = $Self->TicketCustomerWatchGet(
+                TicketID =>       $Ticket{TicketID}
+            );
+            for my $CustomerID (keys %customer) {
+                $Self->SendCustomerWatcherNotification(
+                    Type                  => $Param{HistoryType},
+                    CustomerMessageParams => {%Param},
+                    TicketID              => $Param{TicketID},
+                    UserID                => $Param{UserID},
+                );
+            }
         }
     }
 
@@ -2229,6 +2241,323 @@ sub SendAgentNotification {
     return 1;
 }
 
+
+=item SendCustomerWatcherNotification()
+
+send a customer notification via email
+
+    my $ArticleID = $TicketObject->SendCustomerNotification(
+        Type => 'Move', # notification types, see database
+        CustomerMessageParams => {
+            SomeParams => 'For the message!',
+        },
+        TicketID => 123,
+        UserID   => 123,
+    );
+
+=cut
+
+sub SendCustomerWatcherNotification {
+    my ( $Self, %Param ) = @_;
+
+    # check needed stuff
+    for (qw(CustomerMessageParams TicketID UserID Type)) {
+        if ( !$Param{$_} ) {
+            $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" );
+            return;
+        }
+    }
+
+    # get old article for quoteing
+    my %Article = $Self->ArticleLastCustomerArticle( TicketID => $Param{TicketID} );
+
+    # check if notification should be send
+    my %Queue = $Self->{QueueObject}->QueueGet( ID => $Article{QueueID} );
+    if ( $Param{Type} =~ /^StateUpdate$/ && !$Queue{StateNotify} ) {
+
+        # need no notification
+        return;
+    }
+    elsif ( $Param{Type} =~ /^OwnerUpdate$/ && !$Queue{OwnerNotify} ) {
+
+        # need no notification
+        return;
+    }
+    elsif ( $Param{Type} =~ /^QueueUpdate$/ && !$Queue{MoveNotify} ) {
+
+        # need no notification
+        return;
+    }
+    elsif ( $Param{Type} =~ /^LockUpdate$/ && !$Queue{LockNotify} ) {
+
+        # need no notification
+        return;
+    }
+
+    # check if customer notifications should be send
+    if (
+        $Self->{ConfigObject}->Get('CustomerNotifyJustToRealCustomer')
+        && !$Article{CustomerUserID}
+        )
+    {
+        $Self->{LogObject}->Log(
+            Priority => 'notice',
+            Message  => 'Send no customer notification because no customer is set!',
+        );
+        return;
+    }
+
+    # check customer email
+    elsif ( $Self->{ConfigObject}->Get('CustomerNotifyJustToRealCustomer') ) {
+        my %CustomerUser = $Self->{CustomerUserObject}->CustomerUserDataGet(
+            User => $Article{CustomerUserID},
+        );
+        if ( !$CustomerUser{UserEmail} ) {
+            $Self->{LogObject}->Log(
+                Priority => 'notice',
+                Message  => "Send no customer notification because of missing "
+                    . "customer email (CustomerUserID=$CustomerUser{CustomerUserID})!",
+            );
+            return;
+        }
+    }
+
+    # get language and send recipient
+    my $Language = $Self->{ConfigObject}->Get('DefaultLanguage') || 'en';
+    my %customers = $Self->TicketCustomerWatchGet(
+        TicketID =>       $Param{TicketID}
+    );
+    foreach my $customerUserID (keys %customers) {
+        my %CustomerUser = $Self->{CustomerUserObject}->CustomerUserDataGet(
+            User => $customerUserID,
+        );
+        if ( $CustomerUser{UserEmail} ) {
+            $Article{From} = $CustomerUser{UserEmail};
+        }
+
+        # get user language
+        if ( $CustomerUser{UserLanguage} ) {
+            $Language = $CustomerUser{UserLanguage};
+        }
+    }
+
+    # check recipients
+    if ( !$Article{From} || $Article{From} !~ /@/ ) {
+        return;
+    }
+
+    # get notification data
+    my $NotificationObject = Kernel::System::Notification->new(
+        MainObject   => $Self->{MainObject},
+        DBObject     => $Self->{DBObject},
+        EncodeObject => $Self->{EncodeObject},
+        ConfigObject => $Self->{ConfigObject},
+        LogObject    => $Self->{LogObject},
+        UserObject   => $Self->{UserObject},
+    );
+    my %Notification = $NotificationObject->NotificationGet(
+        Name => $Language . '::Customer::' . $Param{Type},
+    );
+
+    # get notify texts
+    for (qw(Subject Body)) {
+        if ( !$Notification{$_} ) {
+            $Notification{$_} = "No CustomerNotification $_ for $Param{Type} found!";
+        }
+    }
+
+    # prepare customer realname
+    if ( $Notification{Body} =~ /<OTRS_CUSTOMER_REALNAME>/ ) {
+
+        # get realname
+        my $From = '';
+        if ( $Article{CustomerUserID} ) {
+            $From = $Self->{CustomerUserObject}->CustomerName(
+                UserLogin => $Article{CustomerUserID},
+            );
+        }
+        if ( !$From ) {
+            $From = $Notification{From} || '';
+            $From =~ s/<.*>|\(.*\)|\"|;|,//g;
+            $From =~ s/( $)|(  $)//g;
+        }
+        $Notification{Body} =~ s/<OTRS_CUSTOMER_REALNAME>/$From/g;
+    }
+
+    # replace config options
+    $Notification{Body}    =~ s{<OTRS_CONFIG_(.+?)>}{$Self->{ConfigObject}->Get($1)}egx;
+    $Notification{Subject} =~ s{<OTRS_CONFIG_(.+?)>}{$Self->{ConfigObject}->Get($1)}egx;
+
+    # cleanup
+    $Notification{Subject} =~ s/<OTRS_CONFIG_.+?>/-/gi;
+    $Notification{Body}    =~ s/<OTRS_CONFIG_.+?>/-/gi;
+
+    # COMPAT
+    $Notification{Body} =~ s/<OTRS_TICKET_ID>/$Param{TicketID}/gi;
+    $Notification{Body} =~ s/<OTRS_TICKET_NUMBER>/$Article{TicketNumber}/gi;
+    $Notification{Body} =~ s/<OTRS_QUEUE>/$Param{Queue}/gi if ( $Param{Queue} );
+
+    # ticket data
+    my %Ticket = $Self->TicketGet( TicketID => $Param{TicketID} );
+    for ( keys %Ticket ) {
+        if ( defined $Ticket{$_} ) {
+            $Notification{Body}    =~ s/<OTRS_TICKET_$_>/$Ticket{$_}/gi;
+            $Notification{Subject} =~ s/<OTRS_TICKET_$_>/$Ticket{$_}/gi;
+        }
+    }
+
+    # cleanup
+    $Notification{Subject} =~ s/<OTRS_TICKET_.+?>/-/gi;
+    $Notification{Body}    =~ s/<OTRS_TICKET_.+?>/-/gi;
+
+    # get current user data
+    my %CurrentPreferences = $Self->{UserObject}->GetUserData( UserID => $Param{UserID} );
+    for ( keys %CurrentPreferences ) {
+        if ( $CurrentPreferences{$_} ) {
+            $Notification{Body}    =~ s/<OTRS_CURRENT_$_>/$CurrentPreferences{$_}/gi;
+            $Notification{Subject} =~ s/<OTRS_CURRENT_$_>/$CurrentPreferences{$_}/gi;
+        }
+    }
+
+    # cleanup
+    $Notification{Subject} =~ s/<OTRS_CURRENT_.+?>/-/gi;
+    $Notification{Body}    =~ s/<OTRS_CURRENT_.+?>/-/gi;
+
+    # get owner data
+    my %OwnerPreferences = $Self->{UserObject}->GetUserData( UserID => $Article{OwnerID}, );
+    for ( keys %OwnerPreferences ) {
+        if ( $OwnerPreferences{$_} ) {
+            $Notification{Body}    =~ s/<OTRS_OWNER_$_>/$OwnerPreferences{$_}/gi;
+            $Notification{Subject} =~ s/<OTRS_OWNER_$_>/$OwnerPreferences{$_}/gi;
+        }
+    }
+
+    # cleanup
+    $Notification{Subject} =~ s/<OTRS_OWNER_.+?>/-/gi;
+    $Notification{Body}    =~ s/<OTRS_OWNER_.+?>/-/gi;
+
+    # get responsible data
+    my %ResponsiblePreferences = $Self->{UserObject}->GetUserData(
+        UserID => $Article{ResponsibleID},
+    );
+    for ( keys %ResponsiblePreferences ) {
+        if ( $ResponsiblePreferences{$_} ) {
+            $Notification{Body}    =~ s/<OTRS_RESPONSIBLE_$_>/$ResponsiblePreferences{$_}/gi;
+            $Notification{Subject} =~ s/<OTRS_RESPONSIBLE_$_>/$ResponsiblePreferences{$_}/gi;
+        }
+    }
+
+    # cleanup
+    $Notification{Subject} =~ s/<OTRS_RESPONSIBLE_.+?>/-/gi;
+    $Notification{Body}    =~ s/<OTRS_RESPONSIBLE_.+?>/-/gi;
+
+    # get ref of email params
+    my %GetParam = %{ $Param{CustomerMessageParams} };
+    for ( keys %GetParam ) {
+        if ( $GetParam{$_} ) {
+            $Notification{Body}    =~ s/<OTRS_CUSTOMER_DATA_$_>/$GetParam{$_}/gi;
+            $Notification{Subject} =~ s/<OTRS_CUSTOMER_DATA_$_>/$GetParam{$_}/gi;
+        }
+    }
+
+    # get customer data and replace it with <OTRS_CUSTOMER_DATA_...
+    if ( $Article{CustomerUserID} ) {
+        my %CustomerUser = $Self->{CustomerUserObject}->CustomerUserDataGet(
+            User => $Article{CustomerUserID},
+        );
+
+        # replace customer stuff with tags
+        for ( keys %CustomerUser ) {
+            if ( $CustomerUser{$_} ) {
+                $Notification{Body}    =~ s/<OTRS_CUSTOMER_DATA_$_>/$CustomerUser{$_}/gi;
+                $Notification{Subject} =~ s/<OTRS_CUSTOMER_DATA_$_>/$CustomerUser{$_}/gi;
+            }
+        }
+    }
+
+    # cleanup all not needed <OTRS_CUSTOMER_DATA_ tags
+    $Notification{Body}    =~ s/<OTRS_CUSTOMER_DATA_.+?>/-/gi;
+    $Notification{Subject} =~ s/<OTRS_CUSTOMER_DATA_.+?>/-/gi;
+
+    # format body
+    $Article{Body} =~ s/(^>.+|.{4,72})(?:\s|\z)/$1\n/gm if ( $Article{Body} );
+    for ( keys %Article ) {
+        if ( $Article{$_} ) {
+            $Notification{Body}    =~ s/<OTRS_CUSTOMER_$_>/$Article{$_}/gi;
+            $Notification{Subject} =~ s/<OTRS_CUSTOMER_$_>/$Article{$_}/gi;
+        }
+    }
+
+    # prepare subject (insert old subject)
+    $Article{Subject} = $Self->TicketSubjectClean(
+        TicketNumber => $Article{TicketNumber},
+        Subject => $Article{Subject} || '',
+    );
+    if ( $Notification{Subject} =~ /<OTRS_CUSTOMER_SUBJECT\[(.+?)\]>/ ) {
+        my $SubjectChar = $1;
+        $Article{Subject}      =~ s/^(.{$SubjectChar}).*$/$1 [...]/;
+        $Notification{Subject} =~ s/<OTRS_CUSTOMER_SUBJECT\[.+?\]>/$Article{Subject}/g;
+    }
+    $Notification{Subject} = $Self->TicketSubjectBuild(
+        TicketNumber => $Article{TicketNumber},
+        Subject => $Notification{Subject} || '',
+    );
+
+    # prepare body (insert old email)
+    if ( $Notification{Body} =~ /<OTRS_CUSTOMER_EMAIL\[(.+?)\]>/g ) {
+        my $Line       = $1;
+        my @Body       = split( /\n/, $Article{Body} );
+        my $NewOldBody = '';
+        for ( my $i = 0; $i < $Line; $i++ ) {
+
+            # 2002-06-14 patch of Pablo Ruiz Garcia
+            # http://lists.otrs.org/pipermail/dev/2002-June/000012.html
+            if ( $#Body >= $i ) {
+                $NewOldBody .= "> $Body[$i]\n";
+            }
+        }
+        chomp $NewOldBody;
+        $Notification{Body} =~ s/<OTRS_CUSTOMER_EMAIL\[.+?\]>/$NewOldBody/g;
+    }
+
+    # cleanup all not needed <OTRS_CUSTOMER_ tags
+    $Notification{Body}    =~ s/<OTRS_CUSTOMER_.+?>/-/gi;
+    $Notification{Subject} =~ s/<OTRS_CUSTOMER_.+?>/-/gi;
+
+    # send notify
+    my %Address = $Self->{QueueObject}->GetSystemAddress( QueueID => $Article{QueueID} );
+    $Self->ArticleSend(
+        ArticleType    => 'email-notification-ext',
+        SenderType     => 'system',
+        TicketID       => $Param{TicketID},
+        HistoryType    => 'SendCustomerNotification',
+        HistoryComment => "\%\%$Article{From}",
+        From           => "$Address{RealName} <$Address{Email}>",
+        To             => $Article{From},
+        Subject        => $Notification{Subject},
+        Body           => $Notification{Body},
+        MimeType       => 'text/plain',
+        Charset        => $Notification{Charset},
+        UserID         => $Param{UserID},
+        Loop           => 1,
+    );
+
+    # log event
+    $Self->{LogObject}->Log(
+        Priority => 'notice',
+        Message  => "Sent customer '$Param{Type}' notification to '$Article{From}'.",
+    );
+
+    # ticket event
+    $Self->TicketEventHandlerPost(
+        Event    => 'ArticleCustomerNotification',
+        TicketID => $Param{TicketID},
+        UserID   => $Param{UserID},
+    );
+
+    return 1;
+}
+
 =item SendCustomerNotification()
 
 send a customer notification via email
diff --git a/scripts/DB-ticket_customer_watcher.sql b/scripts/DB-ticket_customer_watcher.sql
new file mode 100644
index 0000000..5965930
--- /dev/null
+++ b/scripts/DB-ticket_customer_watcher.sql
@@ -0,0 +1,11 @@
+-- ----------------------------------------------------------
+--  create table ticket_customer_watcher
+-- ----------------------------------------------------------
+CREATE TABLE ticket_customer_watcher (
+    ticket_id INTEGER NOT NULL,
+    customer_user_id VARCHAR(150) NOT NULL,
+    create_time timestamp(0) NOT NULL
+);
+CREATE INDEX ticket_customer_watcher_ticket_id ON ticket_customer_watcher (ticket_id);
+CREATE INDEX ticket_customer_watcher_customer_user_id ON ticket_customer_watcher (customer_user_id);
+ALTER TABLE ticket_customer_watcher OWNER TO otrs;
