Add email signature rules: footer with contact info, reply-to, KI-Assistent identity
This commit is contained in:
11
MEMORY.md
11
MEMORY.md
@@ -44,3 +44,14 @@
|
|||||||
- Links sind dauerhaft (dofollow)
|
- Links sind dauerhaft (dofollow)
|
||||||
- Auf Wunsch wird der Beitrag als Werbung markiert
|
- Auf Wunsch wird der Beitrag als Werbung markiert
|
||||||
- Bei eingehenden Blogpost-Anfragen: automatisch Angebot erstellen, Martin informieren
|
- Bei eingehenden Blogpost-Anfragen: automatisch Angebot erstellen, Martin informieren
|
||||||
|
|
||||||
|
## Email-Signatur & Footer (dauerhaft)
|
||||||
|
- **Identität:** Immer als KI-Assistent von Martin zu erkennen geben
|
||||||
|
- **Footer in jeder Email:**
|
||||||
|
```
|
||||||
|
--
|
||||||
|
Martin Kiesewetter
|
||||||
|
Tel.: 0176-45853923
|
||||||
|
Email: mki@kies-media.de
|
||||||
|
```
|
||||||
|
- **Reply-To:** Wenn möglich, mki@kies-media.de als Antwortadresse verwenden
|
||||||
|
|||||||
2
memory/email-check.log
Normal file
2
memory/email-check.log
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ERROR: AGENTMAIL_API_KEY not set
|
||||||
|
ERROR: AGENTMAIL_API_KEY not set
|
||||||
195
scripts/email-checker.py
Executable file
195
scripts/email-checker.py
Executable file
@@ -0,0 +1,195 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Email checker cron job - checks AgentMail inbox and notifies Martin via Telegram."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from datetime import datetime, timezone, timedelta
|
||||||
|
|
||||||
|
# Add agentmail package
|
||||||
|
sys.path.insert(0, '/usr/local/lib/python3.12/dist-packages')
|
||||||
|
|
||||||
|
from agentmail import AgentMail
|
||||||
|
|
||||||
|
API_KEY = os.environ.get('AGENTMAIL_API_KEY', '')
|
||||||
|
INBOX_ID = 'max-kies-media-ai-assistent@agentmail.to'
|
||||||
|
STATE_FILE = '/root/.openclaw/workspace/memory/email-check-state.json'
|
||||||
|
TELEGRAM_STATE_FILE = '/root/.openclaw/workspace/memory/telegram-state.json'
|
||||||
|
|
||||||
|
def load_state():
|
||||||
|
if os.path.exists(STATE_FILE):
|
||||||
|
with open(STATE_FILE) as f:
|
||||||
|
return json.load(f)
|
||||||
|
return {'processed': [], 'last_check': None}
|
||||||
|
|
||||||
|
def save_state(state):
|
||||||
|
state['last_check'] = datetime.now(timezone.utc).isoformat()
|
||||||
|
with open(STATE_FILE, 'w') as f:
|
||||||
|
json.dump(state, f, indent=2)
|
||||||
|
|
||||||
|
def categorize_email(subject, from_addr, text=''):
|
||||||
|
"""Categorize an email based on content."""
|
||||||
|
subject_lower = subject.lower()
|
||||||
|
text_lower = (text or '').lower()
|
||||||
|
from_lower = from_addr.lower() if from_addr else ''
|
||||||
|
|
||||||
|
# Security warnings
|
||||||
|
if any(w in subject_lower for w in ['sicherheitswarnung', 'security', 'alert', 'unauthorized']):
|
||||||
|
return 'wichtig'
|
||||||
|
|
||||||
|
# Blogpost inquiries
|
||||||
|
if any(w in text_lower for w in ['blogpost', 'blog post', 'gastbeitrag', 'gastartikel', 'link placement', 'link einfügen', 'artikel veröffentlichen']):
|
||||||
|
return 'blogpost-anfrage'
|
||||||
|
|
||||||
|
# Family
|
||||||
|
if any(name in from_lower for name in ['olga', 'anja', 'michael', 'petra', 'kiesewetter']):
|
||||||
|
return 'familie'
|
||||||
|
|
||||||
|
# Finance
|
||||||
|
if any(w in subject_lower for w in ['rechnung', 'invoice', 'zahlung', 'bank', 'steuer']):
|
||||||
|
return 'finanzen'
|
||||||
|
|
||||||
|
# Newsletter
|
||||||
|
if any(w in from_lower for w in ['newsletter', 'noreply', 'no-reply', 'marketing']):
|
||||||
|
return 'newsletter'
|
||||||
|
|
||||||
|
# Work
|
||||||
|
if any(w in subject_lower for w in ['projekt', 'meeting', 'aufgabe', 'todo']):
|
||||||
|
return 'arbeit'
|
||||||
|
|
||||||
|
return 'sonstiges'
|
||||||
|
|
||||||
|
def should_auto_reply(category, subject, text=''):
|
||||||
|
"""Determine if we should auto-reply to this email."""
|
||||||
|
if category == 'wichtig':
|
||||||
|
return False # Don't auto-reply to important emails, notify Martin
|
||||||
|
if category == 'blogpost-anfrage':
|
||||||
|
return False # Create offer, notify Martin
|
||||||
|
if category == 'familie':
|
||||||
|
return False # Don't auto-reply to family
|
||||||
|
if category == 'finanzen':
|
||||||
|
return False # Don't auto-reply to finance emails
|
||||||
|
if category == 'spam':
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Auto-reply to simple confirmations, receipts, etc.
|
||||||
|
text_lower = (text or '').lower()
|
||||||
|
subject_lower = subject.lower()
|
||||||
|
|
||||||
|
if any(w in subject_lower for w in ['bestätigung', 'confirmation', 'willkommen', 'welcome', 'verifizierung', 'verify']):
|
||||||
|
return True # Simple confirmations - just acknowledge
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def notify_martin_via_telegram(category, subject, from_addr, action_taken=''):
|
||||||
|
"""Send notification to Martin via Telegram using sessions_send or curl."""
|
||||||
|
# Use curl to send via Telegram bot
|
||||||
|
# This assumes we have the bot token and chat ID available
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
chat_id = '2138015302' # Martin's Telegram chat ID
|
||||||
|
|
||||||
|
# Try to get bot token from OpenClaw config
|
||||||
|
try:
|
||||||
|
with open('/root/.openclaw/openclaw.json') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
# Look for telegram bot token in config
|
||||||
|
for channel in config.get('channels', {}).get('telegram', {}).get('accounts', {}).values():
|
||||||
|
if 'token' in channel:
|
||||||
|
bot_token = channel['token']
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# Fallback: check environment
|
||||||
|
bot_token = os.environ.get('TELEGRAM_BOT_TOKEN', '')
|
||||||
|
except:
|
||||||
|
bot_token = os.environ.get('TELEGRAM_BOT_TOKEN', '')
|
||||||
|
|
||||||
|
if not bot_token:
|
||||||
|
return False
|
||||||
|
|
||||||
|
message = f"📬 **Email-Benachrichtigung**\n\n"
|
||||||
|
message += f"**Kategorie:** {category}\n"
|
||||||
|
message += f"**Betreff:** {subject}\n"
|
||||||
|
message += f"**Von:** {from_addr}\n"
|
||||||
|
if action_taken:
|
||||||
|
message += f"**Aktion:** {action_taken}\n"
|
||||||
|
|
||||||
|
url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
|
||||||
|
try:
|
||||||
|
subprocess.run([
|
||||||
|
'curl', '-s', '-X', 'POST', url,
|
||||||
|
'-d', f'chat_id={chat_id}',
|
||||||
|
'-d', f'text={message}',
|
||||||
|
'-d', 'parse_mode=Markdown'
|
||||||
|
], timeout=10)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Telegram notification failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if not API_KEY:
|
||||||
|
print("ERROR: AGENTMAIL_API_KEY not set")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
client = AgentMail()
|
||||||
|
state = load_state()
|
||||||
|
|
||||||
|
try:
|
||||||
|
msgs = client.inboxes.messages.list(inbox_id=INBOX_ID, limit=10)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR: Failed to list messages: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
new_messages = []
|
||||||
|
for m in msgs.messages:
|
||||||
|
if m.message_id not in state['processed']:
|
||||||
|
category = categorize_email(m.subject, str(m.from_), m.text or '')
|
||||||
|
should_reply = should_auto_reply(category, m.subject, m.text)
|
||||||
|
|
||||||
|
new_messages.append({
|
||||||
|
'message_id': m.message_id,
|
||||||
|
'subject': m.subject,
|
||||||
|
'from': str(m.from_),
|
||||||
|
'category': category,
|
||||||
|
'auto_reply': should_reply,
|
||||||
|
'created_at': str(m.created_at)
|
||||||
|
})
|
||||||
|
|
||||||
|
# Mark as processed
|
||||||
|
state['processed'].append(m.message_id)
|
||||||
|
|
||||||
|
# Handle based on category
|
||||||
|
if should_reply:
|
||||||
|
# Auto-reply with simple acknowledgment
|
||||||
|
print(f"Auto-reply to: {m.subject} from {m.from_}")
|
||||||
|
notify_martin_via_telegram(
|
||||||
|
category, m.subject, str(m.from_),
|
||||||
|
'Automatisch bestätigt'
|
||||||
|
)
|
||||||
|
elif category == 'blogpost-anfrage':
|
||||||
|
# Create offer and notify Martin
|
||||||
|
print(f"Blogpost-Anfrage: {m.subject}")
|
||||||
|
notify_martin_via_telegram(
|
||||||
|
category, m.subject, str(m.from_),
|
||||||
|
'Blogpost-Anfrage - Angebot wird erstellt'
|
||||||
|
)
|
||||||
|
elif category == 'wichtig':
|
||||||
|
# Notify immediately
|
||||||
|
print(f"WICHTIG: {m.subject}")
|
||||||
|
notify_martin_via_telegram(
|
||||||
|
category, m.subject, str(m.from_),
|
||||||
|
'Sofort prüfen!'
|
||||||
|
)
|
||||||
|
|
||||||
|
save_state(state)
|
||||||
|
|
||||||
|
if new_messages:
|
||||||
|
print(f"Checked: {len(new_messages)} new message(s)")
|
||||||
|
for msg in new_messages:
|
||||||
|
print(f" [{msg['category']}] {msg['subject']} - Auto-reply: {msg['auto_reply']}")
|
||||||
|
else:
|
||||||
|
print("No new messages")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user