jnx aquise mail

main
alex 2024-08-11 11:25:10 +02:00
parent 049084f705
commit 918e19c56a
14 changed files with 583 additions and 2 deletions

View File

@ -0,0 +1,46 @@
<!doctype html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body style="font-family: 'Arial', sans-serif; background-color: #f4f4f4; margin: 0; padding: 0;">
<table
style="width: 100%; max-width: 600px; margin: 20px auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); overflow: hidden; font-size: 0px;"
cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="width: 100%"> <img src="{{topImageSrc}}" alt=""
style="width: 100%; height: auto; border-top-left-radius: 8px; border-top-right-radius: 8px;">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td style="width: 100%; padding: 20px 20px 0 20px; font-size: 16px">
<p style="color: #333; margin: 0 0 15px">{{salutation}}</p>
<p style="color: #333; margin: 0 0 15px">{{text_1}}</p>
<p style="color: #333; margin: 0 0 15px">{{text_2}}</p>
<p style="color: #333; margin: 0 0 15px">{{text_3}}</p>
<a target="_blank" href="{{CTA_Link}}"
style="display: inline-block; padding: 10px 15px; background-color: #4d61d6; color: #fff !important; text-decoration: none !important; border-radius: 5px; margin-top: 20px;"
rel="noopener">{{ctaButton}}</a>
<div style="margin: 20px 0; border-bottom: 1px solid #ddd"></div>
<p style="color: #333; margin: 0 0 15px">{{text_4}}</p>
<p style="color: #333; margin: 0 0 15px">{{text_5}}</p>
<p style="color: #333; margin: 0 0 15px">{{text_6}}</p>
<p style="color: #555; margin: 0"> {{bestRegards}}</p>
</td>
</tr>
</tbody>
</table>
{{footer}}
</td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@ -0,0 +1,22 @@
{{salutation}}
{{text_1}}
{{text_2}}
{{text_3}}
{{ctaButton}}:
---
{{CTA_Link}}
---
{{text_4}}
{{text_5}}
{{text_6}}
{{bestRegards}}
{{footer}}

View File

@ -0,0 +1,43 @@
{
"category": "Jannex",
"name": "Kaltakquise für Shinnex Textegenerator",
"globalInputs": [],
"tasks": [
{
"name": "Gutscheincodes für Bestellung erstellen",
"onFinish": "next",
"undoPossible": false,
"repeatPossible": true,
"scriptPath": "script.py",
"parameters": [
{
"parameterName": "websiteURL",
"type": "text",
"displayName": "URL der Webseite"
},
{
"parameterName": "companyName",
"type": "text",
"displayName": "Firmenname"
},
{
"parameterName": "customerEmail",
"type": "text",
"displayName": "E-Mail vom Kunden",
"required": false
},
{
"parameterName": "customerName",
"type": "text",
"displayName": "Vorname vom Kunden"
},
{
"parameterName": "language",
"type": "select",
"displayName": "Sprache",
"options": ["de", "en"]
}
]
}
]
}

View File

@ -0,0 +1,26 @@
{
"de": {
"subject": "Aw: Textgenerator",
"salutation": "Hey {{customerName}},",
"text_1": "ich hoffe, bei euch im Shop läuft alles rund!",
"text_2": "Wir haben ein Tool entwickelt, das euch eine Menge Zeit sparen könnte: einen Textschild-Generator, der direkt farbige .3mf-Dateien erstellt. Mit diesem Generator könnt ihr problemlos alle Unicode-Zeichen und Emojis darstellen.",
"text_3": "Ihr könnt den Generator kostenlos auf unserer Webseite testen und die generierten Modelle herunterladen. Probiert es einfach aus und lasst uns wissen, wie ihr es findet ;)",
"text_4": "Falls ihr interessiert seid, das Tool auch kommerziell zu nutzen, bieten wir dementsperechend auch eine Lösung an.",
"text_5": "Habt ihr noch Fragen dazu? Meldet euch einfach bei mir!",
"text_6": "Freue mich auf eure Rückmeldung.",
"ctaButton": "Generator ansehen",
"bestRegards": "Mit freundlichen Grüßen\nJan Umbach"
},
"en": {
"subject": "Re: Text generator",
"salutation": "Hey {{customerName}},",
"text_1": "I hope everything is going well in your shop!",
"text_2": "We have developed a tool that could save you a lot of time: a text sign generator that creates colored .3mf files directly. With this generator, you can easily display all Unicode characters and emojis.",
"text_3": "You can test the generator for free on our website and download the generated models. Just give it a try and let us know what you think ;)",
"text_4": "If you are interested in using the tool commercially, we also offer a corresponding solution.",
"text_5": "Do you have any questions about this? Just contact me!",
"text_6": "Looking forward to your feedback.",
"ctaButton": "View generator",
"bestRegards": "Best regards\nJan Umbach"
}
}

View File

@ -0,0 +1,5 @@
requests==2.31.0
reportlab==4.1.0
pdfkit==1.0.0
qrcode==7.4.2
PyPDF2==3.0.1

View File

@ -0,0 +1,277 @@
import requests
import sys
import json
import subprocess
import sys
import os
import string
import random
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../..")))
STATIC_PATH = ""
from libs.utils import utils
# MAIN
# load data from secrets
secrets = utils.get_secrets()
crm_endpoint_url = secrets['admin_dashboard']['url'] + "/api/v1/crm"
headers = {
"X-Api-Key": secrets["admin_dashboard"]["x_api_key"],
"Content-Type": "application/json"
}
json_object = json.loads(sys.argv[1])
customerEmail = json_object["customerEmail"]
customerName = json_object["customerName"]
language = json_object["language"]
companyName = json_object["companyName"]
websiteURL = json_object["websiteURL"]
if (companyName is None
or customerName is None
or language is None
or websiteURL is None):
print("Missing required parameters")
sys.exit(1)
if(customerEmail is not None):
customerEmail = customerEmail["value"]
customerEmail = customerEmail.replace(" ", "")
if(customerEmail == ""):
customerEmail = None
customerName = customerName["value"]
companyName = companyName["value"]
language = language["value"]
websiteURL = websiteURL["value"]
def CreateCrmCustomer():
response = requests.post(
url=f"{crm_endpoint_url}/customer/create",
headers=headers,
json={
"FirstName": customerName,
"Company": companyName,
"Email": customerEmail,
"Website": websiteURL,
"LeadOrigin": "Kaltakquise Email/Contact added by GroupTask",
"DealPhase": 5,
})
print(f"CreateCrmCustomer response status code {response.status_code}")
if response.status_code != 200:
print(f"CreateCrmCustomer req error {response.status_code}")
sys.exit(1)
return response.json()["Id"]
def CheckIfCrmCustomerExists():
print(f"Checking if customer exists: {customerEmail}")
response = requests.post(
url=f"{crm_endpoint_url}/customer",
headers=headers,
json={"Email": customerEmail} # Hier json verwenden, um JSON-Daten zu senden
)
print("CheckIfCrmCustomerExists response status code", response.status_code)
if response.status_code != 200:
print(f"CheckIfCrmCustomerExists req error {response.status_code}")
sys.exit(1)
customerId = ""
# only on first purchase we show the third voucher
if response.json() == []:
print("Customer not found")
customerId = CreateCrmCustomer()
else:
print("Error: Customer already exists")
sys.exit(1)
if len(response.json()) > 1:
print("Multiple customers found. Don't know which one to use")
sys.exit(1)
customerId = response.json()[0]["Id"]
return customerId
def CreateCrmActivityLink(customerId, linkName, linkUrl):
print(f"Creating CRM activity link for customer {customerId}")
_linkName = f"JNX: SHX-Akquise {linkName}"
response = requests.post(
url=f"{crm_endpoint_url}/links",
headers=headers,
json={
"CustomerId": customerId,
"Name": _linkName,
"Url": linkUrl
})
print(f"CreateCrmActivityLink response status code {response.status_code} for {type}")
if response.status_code != 200:
print(f"CreateCrmActivityLink req error {response.status_code}")
sys.exit(1)
response = requests.get(
url=f"{crm_endpoint_url}/customer/view/{customerId}",
headers=headers,
)
print(f"GetCustomerActivityLinks response status code {response.status_code}")
if response.status_code != 200:
print(f"GetCustomerActivityLinks req error {response.status_code}")
sys.exit(1)
data = response.json()["Links"]
if len(data) == 0:
print("No links found")
sys.exit(1)
# sort data by creation date
data = sorted(data, key=lambda x: x["CreatedAt"], reverse=True)
# find the first link that has a name that starts with "Shopify Order #orderId - price € Gutschein"
createdLink = None
for link in data:
if link["Name"].startswith(_linkName):
createdLink = link
break
if(createdLink is None):
print(f"Link with name '{_linkName}' not found")
sys.exit(1)
return secrets["admin_dashboard"]["qr_code_url"] + createdLink['Id']
def sendMail():
secrets = utils.get_secrets()["email"]
# extract the email parameters
auth_email = secrets["auth_email"]
from_email_name = "Jan Umbach"#secrets["from_email_name"]
from_email = "kontakt@jannex.de"#secrets["from_email"]
password = secrets["password"]
# extract the smtp parameters
smtp_server = secrets["smtp_server"]
smtp_port = secrets["smtp_port"]
receiver_email = customerEmail
# create the email multipart message
msg = MIMEMultipart("alternative")
msg["From"] = f"{from_email_name} <{from_email}>"
msg["To"] = receiver_email
# load html content from file
with open(f"{STATIC_PATH}email.txt", "r") as file:
text = file.read()
with open(f"{STATIC_PATH}email.html", "r") as file:
html = file.read()
with open(f"{STATIC_PATH}lang.json", "r") as file:
languageJson = json.load(file)
msg["Subject"] = languageJson[language]["subject"]
# replace placeholders with actual values
# loop through all keys in the language json and replace the placeholders in the html file
for key in languageJson[language]:
value = languageJson[language][key]
value = value.replace("{{customerName}}", customerName)
html = html.replace(f"{{{{{key}}}}}", value.replace("\n", "<br>"))
text = text.replace(f"{{{{{key}}}}}", value)
unsubscribe_link = utils.generate_unsubscribe_link(customerId)
# add link to list-unsubscribe-header
msg["List-Unsubscribe"] = f"<{unsubscribe_link}>"
html = html.replace("{{footer}}", utils.get_email_footer_html(language, unsubscribe_link))
text = text.replace("{{footer}}", utils.get_email_footer_text(language, unsubscribe_link))
html = html.replace("{{topImageSrc}}", CreateCrmActivityLink(customerId, "EMail Opened", "https://jannex.de/unsubscribed/public/shinnex-generator-preview.png"))
html = html.replace("{{CTA_Link}}", CreateCrmActivityLink(customerId, "CTA Clicked (html)", "https://shinnex.de/products/personalisiertes-namensschild?variant=49403793572180"))
text = text.replace("{{CTA_Link}}", CreateCrmActivityLink(customerId, "CTA Clicked (text)", "https://shinnex.de/products/personalisiertes-namensschild?variant=49403793572180"))
print(f"Sending email to {receiver_email}")
print("------")
print(text)
print("------")
if(customerEmail is None):
print("Email not sent because no email address was provided")
return
# add text and html part to the email
part1 = MIMEText(text, "plain", "utf-8")
part2 = MIMEText(html, "html", "utf-8")
# Attach the text and html part to the email
msg.attach(part1)
msg.attach(part2)
# connect to the smtp server and send the email
try:
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.login(auth_email, password)
server.sendmail(from_email, receiver_email, msg.as_string())
print(f"Email sent to {receiver_email}")
except Exception as e:
print(f"Error sending email: {e}")
sys.exit(1)
if __name__ == "__main__":
utils.move_files_back_from_old_files()
if(customerEmail is not None):
customerId = CheckIfCrmCustomerExists()
else:
customerId = CreateCrmCustomer()
sendMail()
utils.clear_workspace(["email.html", "email.txt", "lang.json"])

View File

@ -1,6 +1,5 @@
import json
import sys
import yaml
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

View File

@ -0,0 +1,14 @@
<table cellspacing="0" cellpadding="0"
style="width: 100%; margin: 20px auto; padding: 10px 20px 0 20px; font-size: 0px">
<tbody>
<tr>
<td
style="font-size: 12px; width: 100%; padding: 10px 20px 0 20px; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px;">
<p style="color: #333; margin: 0; font-size: 12px"> <i>{{rechtstext}}</i>
</p>
<p style="color: #333; margin: 15px 0; font-size: 12px">{{impressum}}</p>
<p style="color: #333; margin: 15px 0; font-size: 12px">{{unsubscribe_text}}</p>
</td>
</tr>
</tbody>
</table>

View File

@ -0,0 +1,6 @@
{{rechtstext}}
{{impressum}}
{{unsubscribe_text}}
{{unsubscribeLink}}

View File

@ -0,0 +1,14 @@
{
"de": {
"rechtstext": "Diese E-Mail enthält vertrauliche und/oder rechtlich geschützte Informationen. Wenn Sie nicht der richtige Adressat sind oder diese E-Mail irrtümlich erhalten haben, informieren Sie bitte sofort den Absender und vernichten Sie diese Mail. Das unerlaubte Kopieren sowie die unbefugte Weitergabe dieser Mail ist nicht gestattet.",
"impressum": "Impressum:\nJan Umbach, Tannenwäldchen 20, DE-34212 Melsungen",
"unsubscribe_text": "Wenn Sie keine weiteren E-Mails von uns erhalten möchten, klicken Sie bitte {{unsubscribe_text_button}}.",
"unsubscribe_text_button": "hier"
},
"en": {
"rechtstext": "This email contains confidential and/or proprietary information. If you are not the intended recipient or have received this email in error, please notify the sender immediately and destroy this email. Unauthorized copying and unauthorized distribution of this email is prohibited.",
"impressum": "Imprint:\nJan Umbach, Tannenwäldchen 20, DE-34212 Melsungen",
"unsubscribe_text": "If you do not want to receive any more emails from us, please click {{unsubscribe_text_button}}.",
"unsubscribe_text_button": "here"
}
}

View File

@ -201,3 +201,132 @@ def create_shopify_discount_code(shopify_discount_code_price_rule_name):
print(f"Created discount code: {generated_discount_code}. Retries: {retries}")
return generated_discount_code
def get_email_footer_html(language, unsubscribe_link):
languageJson = None
with open("../../groupsData/jnx-email-template/lang.json", "r") as file:
languageJson = json.load(file)
with open("../../groupsData/jnx-email-template/footer.html", "r") as file:
content = file.read()
def replace_unsubscribe_text_button(content):
return content.replace("{{unsubscribe_text_button}}", f"<a href='{unsubscribe_link}'>{languageJson[language]['unsubscribe_text_button']}</a>")
# loop through all keys in the language json and replace the placeholders in the html file
for key in languageJson[language]:
if(key == "unsubscribe_text_button"):
content = replace_unsubscribe_text_button(content)
else:
value = languageJson[language][key]
value = value.replace("\n", "<br>")
content = content.replace(f"{{{{{key}}}}}", value)
content = replace_unsubscribe_text_button(content)
content = content.replace("{{unsubscribeLink}}", unsubscribe_link)
return content
def get_email_footer_text(language, unsubscribe_link):
languageJson = None
with open("../../groupsData/jnx-email-template/lang.json", "r") as file:
languageJson = json.load(file)
with open("../../groupsData/jnx-email-template/footer.txt", "r") as file:
content = file.read()
# loop through all keys in the language json and replace the placeholders in the html file
for key in languageJson[language]:
content = content.replace(f"{{{{{key}}}}}", languageJson[language][key])
content = content.replace("{{unsubscribe_text_button}}", languageJson[language]['unsubscribe_text_button'])
content = content.replace("{{unsubscribeLink}}", unsubscribe_link)
return content
def generate_unsubscribe_link(customerId):
print(f"Using CRM unsubscribe link for customer {customerId}")
_linkName = f"JNX: ⛔️⛔️⛔️ WARN - E-Mail unsubscribed ⛔️⛔️⛔️"
_secrets = get_secrets()
crm_endpoint_url = _secrets['admin_dashboard']['url'] + "/api/v1/crm"
headers = {
"X-Api-Key": _secrets["admin_dashboard"]["x_api_key"],
"Content-Type": "application/json"
}
def get_link():
response = requests.get(
url=f"{crm_endpoint_url}/customer/view/{customerId}",
headers=headers,
)
print(f"GetCustomerActivityLinks response status code {response.status_code}")
if response.status_code != 200:
print(f"GetCustomerActivityLinks req error {response.status_code}")
sys.exit(1)
data = response.json()["Links"]
if len(data) == 0:
print("No links found")
return None
# sort data by creation date
data = sorted(data, key=lambda x: x["CreatedAt"], reverse=True)
# find the first link that has a name that starts with "Shopify Order #orderId - price € Gutschein"
createdLink = None
for link in data:
if link["Name"].startswith(_linkName):
createdLink = link
break
if(createdLink is None):
print(f"Unsubscribe link not found, creating new one")
return None
return _secrets["admin_dashboard"]["qr_code_url"] + createdLink['Id']
link = get_link()
if(link is not None):
print(f"Using existing unsubscribe link for customer {customerId}")
return link
print(f"Creating CRM unsubscribe link for customer {customerId}")
response = requests.post(
url=f"{crm_endpoint_url}/links",
headers=headers,
json={
"CustomerId": customerId,
"Name": _linkName,
"Url": "https://jannex.de/unsubscribed"
})
print(f"CreateCrmActivityLink response status code {response.status_code} for {type}")
if response.status_code != 200:
print(f"CreateCrmActivityLink req error {response.status_code}")
sys.exit(1)
link = get_link()
if(link is None):
print("Error creating unsubscribe link")
sys.exit(1)
return link

BIN
main

Binary file not shown.

View File

@ -18,7 +18,7 @@ const (
MaxRoleDescription = 80
MaxEquipmentDocumentationTitleLength = "60"
MaxEquipmentDocumentationNoteLength = 2000
MaxNoficationTitleLength = "255"
MaxNoficationTitleLength = "4096"
MinUserApiKeyNameLength = 2
MaxUserApiKeyNameLength = 30