PHP/MYSQL: Nachrichten-System

Georgler

PC-Selbstbauer(in)
Hi,

ich bin gerade am Arbeiten an einem Nachrichten-Modul.
Damit soll es möglich sein, mehreren Gruppen und/oder mehreren Benutzern Nachrichten zu schreiben (über die Datenbank).

Folgende Datenbanktabelle habe ich mir überlegt:
| id | empfaenger_id | switch | absender_id | betreff | nachricht | gelesen | del | zeitpunkt |

Ich habe mir gedacht man definiert in der Spalte "switch", ob es an eine Gruppe oder an einen Benutzer gesendet wird (ENUM 'user_id', 'group_id').
Wenn beispielsweise in der Switch-Spalte "user_id" steht, wird die Spalte empfaenger_id als user_id gewertet, genauso bei Gruppen.

In der Spalte "gelesen" wird protokolliert, ob der Benutzer die Nachricht gelesen hat, damit beispielsweise auf der Startseite nicht angezeigt wird, dass man neue Nachrichten habe. Doch wie kann man das am besten umsetzen? Ich dachte spontan an ein Mousover (d.h. mit der Maus über den Text der Nachricht fahren), aber wenn man dann bei jedem Mouseover eine DB-Query macht, ich weiß ja nicht.
Oder wäre es einfach besser eine Liste mit den Betreffen anzuzeigen und sobald man auf den Betreff klickt wird die DB-Query ausgeführt?

In der Spalte "del" wird dann gesagt, ob der Absender die Nachricht gelöscht haben wollte -> sie wird dem Empfänger nicht mehr angezeigt. Oder sollte man sie dann nicht einfach ganz löschen?

Soweit der Plan, doch jetzt kam mir ein grundlegendes Problem entgegen. Das funktioniert nur als 1 Absender zu 1 Empfänger, ich wollte es aber gerade mit mehreren Empfängern haben und dann sollen die Empfänger noch unterschiedlich sein können (d.h. Gruppen und Benutzer dürfen Empfänger sein bei der selben Nachricht).

Wie muss ich da vorgehen? Ich dachte jetzt spontan an eine zweite Tabelle die dann die Id der Nachricht (Tabelle nachrichten) mit den Benutzer-IDs und Gruppen-IDs verknüpft.
Ungefähr so:
| nachricht_id | empfaenger_id | switch |

Doch wie müsste nun eine Query zum Eintragen und zum Abfragen aussehen?
Für das Absenden bräuchte man dann ja auf jeden Fall mehrere Querys.

Beim Abfragen einen Nachricht:
Code:
SELECT
    n. id,
    n. absender_id,
    n.betreff,
    n.nachricht,
    n.zeitpunkt
FROM nachrichten n
LEFT JOIN nachrichten_empfaenger ne
    ON ne.nachricht_id = n.id
WHERE ((ne.empfaenger_id = ? AND ne.switch = ? ) OR (gucken ob benutzer in einer gruppe ist, die die nachricht bekommen hat)) AND n.del != ?
erstes Fragezeichen: aktuelle user_id
zweites Fragezeichen: "user_id"
drittes Fragezeichen: "1"

Hierbei habe ich keine Idee, wie der Gruppen-Teil aussehen kann.

Achja, meine Gruppen-Tabelle (groups):
| group_id | group_name |

Die Tabelle mit den Gruppen-Benutzer-Zuordnungen (users_groups):
| user_id | group_id |

MfG
 
Da gibt es sehr viele verschiedene Ansätze, wie man das lösen kann. Allerdings kannst du die reine Gruppenzuordnung von Nachrichten vollkommen vergessen. Denn wenn ein Nutzer die Nachricht löscht, muss die Nachricht für ihn auch verschwinden. Deswegen würde ich für die Nachrichten mit 2 Tabellen arbeiten. Mit einer Message_Data Tabelle und mit einer Message_Link Tabelle:
Message_Data:
| msg_id | msg_subject | msg_body |

Message_Link:
| msgl_sender (Absender-ID) | msgl_addressee (Empfänger-ID) | msgl_message (ID der Nachricht) |

So könnte der Inhalt der Tabellen aussehen
Message_Data:
| 21 | "Hallo ihr 5" | "So kann eine Gruppennachricht gespeichert werden" |

Message_Link:
| 1 (Benutzer 1 als Absender) | 3 (Benutzer 3 als Empfänger) | 21 (ID der Nachricht)
| 1 (Benutzer 1 als Absender) | 11 (Benutzer 11 als Empfänger) | 21 (ID der Nachricht)
| 1 (Benutzer 1 als Absender) | 23 (Benutzer 23 als Empfänger) | 21 (ID der Nachricht)
| 1 (Benutzer 1 als Absender) | 51 (Benutzer 51 als Empfänger) | 21 (ID der Nachricht)
| 1 (Benutzer 1 als Absender) | 39 (Benutzer 39 als Empfänger) | 21 (ID der Nachricht)

Die Gruppenzugehörigkeit kannst du dann über die jeweilige Benutzer und Gruppentabelle erledigen. Dazu holst du dir mit einem Query die Liste mit den ID's und bastelst dann einen langen Insert für die Tebelle mit den Links. Aber das ist noch einfach. Etwas komplexer wird es, die Nachrichten-ID dort hinnein zu bekommen. Aber auch da gibt es verschiedene Anasätze. Du könntest mit Subquerries arbeiten, die Nachricht nach dem Einfügen samt ID nochmal abfragen oder mit der PDO-Methode lastinsertid versuchen, die ID in die Spalte zu schreiben.

Das ganze ist zwar etwas fummeliger. Dafür funktioniert der Spaß perfekt. Löscht nämlich ein User die Nachricht, wird nur der Eintrag aus Message_Link gelöscht. Die anderen können die Nachricht aber weiterhin lesen. Redundanz gibt es ebenfalls nicht. Beim Löschen einer Nachricht kannst du den Request dafür nutzen um zu schauen, ob die Nachrichten-ID überhaupt noch jemanden zugewiesen ist. Wenn nicht, löscht du die Nachricht aus der Nachrichten-Tabelle.
 
Hi,

vielen Dank für deine Hilfe und vor allem die Tabelle msg_link!

Ich habe bis jetzt das und wollte einfach mal wissen, ob das überhaupt in Ordnung ist. Ich habe ein bisschen getestet und bisher habe ich keine Probleme festgestellt. Ein Problem wäre es, wenn wer die Nachricht angezeigt bekommt, der dafür gar nicht berechtigt ist. :D

Meine Datenbank-Tabellen:
msg_data:
| id | betreff | nachricht | zeitpunkt |

msg_link
| user_id (-> Absender) | switch (-> entweder "user" oder "group") | to_id (->Empfänger) | msg_id (-> ID der Nachricht aus msg_data) | gelesen (noch keine Funktion) |

Anmkerung: Wenn in der Spalte switch "user" steht wird die Spalte to_id als user_id gewertet. Das gleiche auch bei group.

users
| user_id | username | realname |

groups
| group_id | group_name |

users_groups (Linking-Tabelle: gibt an welcher Benutzer in welcher Gruppe ist)
| user_id | group_id |

Hier mein Code (bisher nur zum Abfragen und Anzeigen der Betreffe):
PHP:
$group_switch = 'group';
$user_switch = 'user';
$sql = $db->prepare("
	SELECT 
		md.id,
		md.betreff,
		md.zeitpunkt,
		u.realname,
		u.username
	FROM msg_data md
	LEFT JOIN msg_link ml
		ON ml.msg_id = md.id
	LEFT JOIN users_groups ug
		ON ug.group_id = ml.to_id
	LEFT JOIN users u
		ON ml.user_id = u.user_id
	WHERE (ug.user_id = ? AND switch = ?) OR (to_id = ? AND switch = ?)
	ORDER BY md.zeitpunkt DESC
	LIMIT 150
");
$sql->bind_param('isis', $user_id, $group_switch, $user_id, $user_switch);
$sql->execute();
$sql->store_result();
$sql->bind_result($msg_id, $msg_betreff, $msg_zeitpunkt, $msg_realname, $msg_username);

if ($sql->num_rows == 0) {
	echo'Keine Nachrichten verfügbar.';
} else {
	while ($sql->fetch()) {
		echo'
		<b>Nachricht-ID:</b><br>
		'.$msg_id.'<br><br>
		<b>Absender:</b><br>
		'.$msg_realname.' ('.$msg_username.')<br><br>
		<b>Nachricht-Betreff:</b><br>
		'.$msg_betreff.'<br><br>
		<b>Nachricht-Zeitpunkt:</b><br>
		'.date('d.m.Y H:i', strtotime($msg_zeitpunkt)).'
		<hr>
		';
	}
}

Edit:
Ich bin gerade auf ein kleines Problem gestoßen von wegen Unqiue Key.
phpmyadmin hatte mich gewarnt, dass die Tabelle msg_link keinen Unique Key hatte.
Dann habe ich folgenden Befehl ausgeführt: ALTER TABLE msg_link ADD UNIQUE KEY (user_id, to_id, switch, msg_id)

Ich dachte immer wenn man das so macht, dann ist nur die Kombination von den 4 Feldern einzigartig. Aber als ich dann einen neuen Eintrag machen wollte mit der selben user_id kam der Fehler: Duplicate Entry.

Brauche ich für die Tabelle überhaupt einen Unique Key oder habe ich etwas falsch gemacht?
 
Zuletzt bearbeitet:
Für diese Tabelle brauchst du eigentlich keinen Unique. Bei mir klappen Tabellen ohne Keys.



Ich verstehe auch dein ganzes Rumspielen mut der Gruppe und dem Switch nicht. Den Quatsch brauchst du nicht. Wenn eine Nachricht an eine Gruppe gehen soll, dann holst du dir die Mitglieder-ID's einer Gruppe aus der Datenbank und speicherst für "jeden" Empfänger in der Linktabelle einen Datensatz. Den Vorteil dadurch hatte ich ja schon genannt. Jeder Nutzer kann seine Nachricht unabhängig von alles anderen Empfängern löschen. Wenn du eine Nachricht einer Gruppe zuweist, kann ein einzelner die Nachricht für sich nicht löschen, ohne das du den Hinweis auf die Löschung noch anderweitig speicherst (z.B. eine weitere Tabelle). Aber das ist unnötig und erhöht nur die Anzahl der Querries. Du machst es dir also nur unnötig kompliziert.
 
Ok, ich habe das mit dem switch entfernt, ist mir gar nicht aufgefallen, dass man damit die Möglichkeit des Löschens/Ausblenden wegwirft.
Ich habe jetzt noch eine Spalte in der msg_data-Tabelle hinzugefügt, in der als String gespeichert wird, an wen die Nachricht geschickt wurde. Ich wollte unbedingt, dass wenn man etwas an eine Gruppe schickt, dass dort auch steht, dass es an jene Gruppe geschickt wurde.

Noch eine kleine Frage:Ich hatte überlegt, dass wenn man in einem Textfeld einen Benutzernamen eingibt, dass einem dann automatisch aus der Datenbank entsprechende Ergebnisse zum Anklicken vorgezeigt werden. Sollte man vorher alle Benutzernamen aus der Datenbank holen sollte und in einen Array speichern? Ich weiß aber nicht nicht, ob das Geschwindigkeitseinbußen geben könnte. Andernfalls müsste man ja mit einem change-Event eine SQl-Query ausführen, aber das wäre ja auch suboptimal, wenn man immer wieder ein Zeichen eingibt und diese kleine Auswahl an Benutzern immer neu geladen wird.

So etwas kann ja das autocomplete-Ding von jQueryUI aber kann man das auch für eine Mehrfachauswahl nutzen?
 
Mit autocomplete habe ich jetzt nicht so die Erfahrung. Aber soweit ich weiß, reicht theoretisch ein Query aus. Sobald du z.B. die ersten 3 Zeichen eingibst lässt du dir per Ajax alle Einträge mit den 3 Zeichen beginnen als Array zurückliefern. Die restliche Suche übernimmt dann das Javascript. Aber du solltest das ganze sehr Behutsam gegen Missbrauch absichern und nur das nötigste ins Array speichern. Sonst wird es hässlich. Bei großen Tabellen wie bei der Googlesuche wird sehr viel mit caching und der Wahrscheinlichkeit gearbeitet. Aber bei kleineren Sachen wird das nicht nötig sein.
 
Wie sollte man sich da gegen Missbrauch absichern? Ich habe einfach folgende Query:

Code:
SELECT username FROm users WHERE user_id != 2

Die letzte Bedinung soll einfach nur dafür sorgen, dass man keine Nachrichten an den "System"-Benutzer schicken kann.
Ich nutze hierfür einfach eine normale Query, kein Prepared Statement. Gibt es da Sicherheitslücken in meiner Vorgehensweise?

Edit: Ich bin gerade am testen, Nachrichten in die Datenbank zu schreiben und ich muss jetzt mehrere Querys auf einmal machen. Wie mache ich das am besten, geht das auch mit Prepared Statements (also um SQL injections zu verhindern)?

Ebenfalls müsste ich die automatisch generierte ID der Nachricht (in msg_data) kriegen, um dann in der zweiten Query erfolgreich zu verknüpfen.

Bisher sind das meine Queries (alle Variablen gegeben, auch wenn sie da jetzt nicht alle stehen, da die POST-Variablen bei mir erstmal durch eine Fehlerroutine durchlaufen):
PHP:
$user_id = $_SESSION["user_id"];
$zeitpunkt = date('d.m.Y H:i');
$null = 0;

$sql = $db->prepare("INSERT INTO msg_data (betreff, nachricht, zeitpunkt, to_string) VALUES (?, ?, ?, ?)");
$sql->bind_param('ssss', $input_betreff, $input_nachricht, $zeitpunkt, $input_username);

$sql = $db->prepare("INSERT INTO msg_link (user_id, to_id, msg_id, gelesen) VALUES (?, ?, ?, ?)");
$sql->bind_param('ssss', $user_id, $to_user_id, $LASTINSERTEDID, $null);
 
Zuletzt bearbeitet:
LastInsertedId ist eine PDO Methode. So sollte es nicht funktionieren. Außerdem kannst du auch mehrere Datensätze auf einmal mit einem Insert-Query in die Datenbank schreiben. Dafür musst du nur die Werte in Klammern mit Komma getrennt in den Query reinpacken. z.B.
Code:
INSERT INTO users (id,name) VALUES (1,"HUHU"),(2,"Haha"),(3,"Hehe")
Da hilft eine foreach-Schleife unheimlich. Du musst halt nur garantieren, das der String das passende Format hat.

Dein erster Query liefert dir ja alle Benutzernamen zurück. Am sinnvollsten wäre es aber, wenn du die Liste zumindest mit den ersten beiden Buchstaben eingrenzt. Also 2 Buchstaben eingeben, Ajax-Anfrage mit Query auf die Datenbank und Array als z.B. JSON zurück ans Autocomplete. Denn gerade bei größeren Projekten mit vielen Nutzern (100.000 aufwährts) kann so ein JSON Array/Objekt schon einmal die MB-Grenze knacken und bei langsameren Verbindungen zu unangenehmen Latenzen führen.
 
@DarMo: Ich erwähnte es ja nur, da er PDO nutzt :D

@Georgler: Du brauchst für jede Tabelle ein Query. Zuerst speicherst du die Nachricht in der entsprechenden Tabelle. Erst dann funktioniert auch erst lastinsertedid. Dann baust du den Query, wo du die Nachricht (über lastinsertedid) in der Linktabelle den Empfängern zuordnest so wie ich es im letzten Beitrag geschrieben hatte mit den Kommata. Und dann läuft es schon problemlos.
 
Muss ich die zwei Queries komplett trennen oder lassen die sich in einem Block abarbeiten? Also die erste Query wäre die, wo man die Nachricht in die Tabelle einträgt und die zweite Query wäre die, wo man die ganzen Zuordnungen in die Datenbank schreibt (mehrere Zuordnungen möglich).

Ich habe da irgendwas mit BEGIN oder COMMIT im Kopf?

Beispiel, wie ich es mir vorstelle:
PHP:
$sql = $db->prepare("
    BEGINN;
    INSERT INTO msg_data (betreff, nachricht, ...) VALUES (?, ?, ...);
    INSERT INTO msg_link (hier dann noch eine foreach-Schleife je nachdem, an wie viele Benutzer man gesendet hat)
    COMMIT;
")
$sql->bind_param(...);
$sql->execute();
 
Transaktionen sammeln im Grunde nur Querries und führen sie auf einen Schlag aus. In diesem Falle funktioniert nur lastinsertedid nicht und du kannst die Zuordnung nicht machen. Du musst also in diesem speziellen Fall trennen.
 
Normalerweise verhalten sich Transaktionen schon wie "echte" Kommandos, die werden nur erst beim COMMIT persistent in die entsprechenden Tabellen geschrieben.
 
Ok, ich habe es jetzt so gemacht, dass erst wenn die erste Query erfolgreich ausgeführt wurde, die zweite Query ausgeführt wird. Das klappt auch soweit.

Ich habe nur noch eine Frage bzgl. der Tabellenstruktur.

Macht es nicht Sinn den Absender der Nachricht in msg_data zu speichern? Sonst kann man ja als Autor gar nicht seine eigene Nachricht löschen und man hat sehr viele Redundanzen in der msg_link-Tabelle, weil dort überall die gleiche user_id steht, wenn man die Nachricht an mehrere Leute schickt.
 
Diese "Redundanzen" sind in diesem Fall aber nötig. Denn jede Nachricht stellt eine einzelne Einheit dar. Wenn du diese "Redundanz" entfernen wollen würdest, hast du promt wieder die selben Probleme wie am Anfang. Du müsstest die Nachrichten wieder als Gruppe in einen Datensatz stecken, was dann mal wieder darin endet, das die Nachricht nicht mehr für jeden Empfänger einzeln behandelbar ist. Bei einem Onlineshop kannst du ja auch nicht alle Bestellungen in einen Datensatz bündeln, nur weil sonst bei den Datensätzen überall die selbe ID drin steht.

Zum Thema Autor: Eine Nachricht sollte nur gelöscht werden, wenn alle Empfänger sie löschen. Wenn der Autor die Nachricht versendet hat, ist sie weg. Ist bei Post und E-Mail ja auch so ;)
 
Aber ist die Kombination von msg_id und to_id (Empfänger) nicht eindeutig?

Dann könnte man doch einfach nach dem Schema löschen, oder?: DELETE FROM msg_link WHERE msg_id = jeweiligeNachricht AND to_id = $_SESSION["user_id"]

Dann wären die Tabellen folgende:
msg_link
| to_id | msg_id | gelesen |

msg_data
| user_id (Absender) | msg_id | betreff | nachricht | zeitpunkt |
 
Achsooo meinste das. Ja das wäre auch eindeutig. Aber wie schon gesagt ist die Form von Redundanz gehüpft wie gesprungen. Du hast zwar bei den Links ne Spalte weniger. Aber weder Aufwand noch Datenbestand ändern sich da großartig. Und nachträglich nach dem Senden der Nachricht sollte der Autor weder löschen noch bearbeiten können.
 
Wieso eigentlich nicht? Weil's der Standard ist wahrscheinlich oder? :D

Ich bin jetzt gerade dabei zu implementieren, dass man mehrere Benutzer auswählen kann.

Gefunden habe ich da das jQuery UI Autocomplete (multiple, remote): https://jqueryui.com/autocomplete/#multiple-remote

Das erfüllt genau das geforderte: mehrere Auswahlmöglichkeiten, alles wird per Datenbank abgefragt und man muss mindestens 2 Zeichen eingeben.

Dann kommt da ein Code wie dieser: $.getJSON( "search.php". Jetzt ist die Frage, wie muss der Code in dieser search.php aussehen? Habe mich mit JSON nie so richtig beschäftigt, gibt es da gute Dokumentationen?

Edit (der funktioniert allerdings nicht):

Code:
      $(function() {
	        function split( val ) {
	                  return val.split( /,\s*/ );
               }
		function extractLast( term ) {
			  return split( term ).pop();
		}
	 
		$("#msg_empfaenger")
			.bind( "keydown", function( event ) {
				if ( event.keyCode === $.ui.keyCode.TAB &&
					$( this ).autocomplete( "instance" ).menu.active ) {
					event.preventDefault();
				}
			})
			.autocomplete({
				source: function( request, response ) {
					$.getJSON( "msg_neu_array.php", {
					term: extractLast( request.term )
				}, response );
			},
			search: function() {
				var term = extractLast( this.value );
				if ( term.length < 3 ) {
					return false;
				}
			},
			focus: function() {
				return false;
			},
			select: function( event, ui ) {
				var terms = split( this.value );
				terms.pop();
            			terms.push( ui.item.value );
				terms.push( "" );
				this.value = terms.join( ", " );
				return false;
			}
		});
	});

PHP:
//Variablen + ErrorHandling
	if (isset($_POST["term"])) {
		$input_term = $_POST["term"];
	} else {
		exit; 
	}
	$user_id = $_SESSION["user_id"];
	$term2 = '%'.$term.'%';
	
	//SQL
	$sql = $db->prepare("SELECT username FROM users WHERE username LIKE ?");
	$sql->bind_param('s', $term2);
	if ($sql->execute()) {
		$sql->store_result();
		$sql->bind_result($username);
		while ($sql->fetch()) {
			$usernames[] = $username;
		}
		echo json_encode($usernames);
	} else {
		exit;
	}
 
Zuletzt bearbeitet:
Das mit JSON ist ganz ganz einfach. Auch wenn man mit echo in PHP nach und nach eine HTML-Konforme Website zusammenschustert, liefert es im Grunde nur Plain-Text, der auf Grund seiner Struktur und seines MIME-Types interpretiert wird. Ist der MIME ein HTML-Dokument, wird der mit echo geschriebene Text ausgegeben. Befindet sich nun aber ein HTML-Tag in diesem Text, wird er vom HTML-Parser ausgewertet und interpretiert. Auch für JSON gibt es MIME-Types. Dadurch weißt der Browser, das die Rückgabe ein Plain-Text für Javascript ist.

Du musst also in PHP dafür sorgen, das der MIME-Type passt und das die Daten in ein JSON-String umgewandelt und ausgegeben werden. Dafür gibt es in PHP die Funktionen json_encode (Array oder Objekt zu JSON-String) oder json_decode (JSON-String zu Array). Das ganze funktioniert ähnlich dem Serialisieren eines Arrays mit serialize() oder unserialize(). Ist also vollkommen einfach. Es gibt also nur 4 Dinge, die du beachten musst:
1. Prüfen, ob der Request ein AJAX-Request war!
2. Du lieferst kein HTML oder andere Daten mit dem Script aus!
3. Die Rückgabe muss JSON-Konform sein. Nutze also am besten die Funktion json_encode dafür!
4. Setze vor der Ausgabe einen passenden MIME-Type über den Header, damit der Browser weiß, was für eine Buchstabensuppe er da bekommt!

Hier einmal ein kleines JSON-Beispiel: Demo: jQuery Ajax Call to PHP Script with JSON Return — Jonathan Suh Labs
Da aber der Typ dort den MIME-Type vergessen hat, hier noch einmal etwas zu dem Thema: What is the correct JSON content type? - Stack Overflow

Und zu deiner Frage zwecks Standard beim Bearbeiten und Löschen von Nachrichten:
Es ist ein großer Unterschied, ob man nun ein öffentliches Forum oder einen nicht-öffentlichen Nachrichtendienst anbietet. Während in einem öffentliches Forum jeder anwesende dort eine Diskussion oder einen Verlauf mitverfolgen kann, so ist das in der privaten bzw. nicht-öffentlichen Kommunikation nicht der Fall. Private Kommunikation benötigt daher eine größere Vertrauengrundlage, da meist die Öffentlichkeit das geschriebene nicht sehen und deswegen auch niemand da ist, auf den man sich beziehen kann. Daher ist es wichtig, das ein Verfasser/Absender nach dem Absenden keinerlei Einfluss mehr auf den Inhalt nehmen kann. Das geschriebene Wort bleibt also so stehen, wie es abgesendet wurde und man kann sich als Empfänger genau darauf beziehen. Genau das ist auch der Grund dafür, warum viele Firmen und Unternehmen selbst intern eigene Mailserver wie Exchange, Mercury, Postfix etc. verwenden, anstatt auf Datenbankbasierte Lösungen wie so eine Nachrichtenfunktion zu setzen.

Gerade in Zeiten von Cybermobbing oder Mobbing am Arbeitsplatz wäre so eine Funktion fatal. Man könnte sich darüber beleidigen und wenn es gelesen wurde einfach vom Absender bearbeitet oder gelöscht werden. Das würde das Vertrauen in die Software, in dessen Entwickler und auch in das Projekt, das diese Software einsetzt, extrem schädigen. Private bzw. nicht-öffentliche Kommunikation sollte also fest protokollierbar bleiben. Und das bedeutet eben, das der Text, der gesendet wurde, so auch bestehen bleibt. Ein Mailserver zum Beispiel arbeitet nach festen Standards. Wird eine Email versendet, so kann nur noch ein Abministrator mit vollem Zugriff die Nachricht aus dem System entfernen. Aber nicht der Absender selber. Wenn also ein Absender der Meinung ist, durch den Inhalt einer Nachricht gegen geltendes Recht verstoßen zu müssen, so kann diese Nachricht vom Empfänger archiviert und der Betreiber des Servers damit konfrontiert werden (natürlich nur Unternehmensintern oder in Arbeitsgruppen/Projekten sinnvoll). Der Betreiber kann dann auch selbst auf den Server schauen, den Umstand bestätigen und entsprechende Konsequenzen ziehen. Ähnlich ist es auch, wenn du die Funktionen weglässt. Dadurch kommt ebenfalls nur noch ein Datenbankadmin an die Nachricht, um sie systemweit zu löschen/zu ändern (es sei denn der/die Empfänger löschen sie alle ... das wäre dann aber auch eigene Dummheit!). Um es also auf den Pubnkt zu bringen: Wenn ein Absender seine Nachrichten nach dem senden bearbeiten oder löschen kann, dann kann er sich auch der Verantwortung/Haftung für den Inhalt entziehen.
 
Zurück