Compare commits
8 Commits
df99a03936
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5b20a71de | ||
|
|
a902f5a685 | ||
|
|
153ba885c8 | ||
|
|
4ff791d9fe | ||
|
|
2df6e67ffb | ||
|
|
8165ee9970 | ||
|
|
47e698a4fe | ||
|
|
62a11e258a |
23
LICENSE.txt
Normal file
23
LICENSE.txt
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
send_mail
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Handmade Cities
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
45
README.md
Normal file
45
README.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
------
|
||||||
|
**DISCLAIMER: This project is very much a Work In Progress. It is for meetup hosts pioneering Handmade Meetups. Hosts are expected to be programmers comfortable with command-line programs. You can get help or give feedback in the [`#meetups`](https://discord.com/channels/239737791225790464/424523844016144394) channel of the [Handmade Network Discord](https://discord.gg/hmn).**
|
||||||
|
------
|
||||||
|
# send_mail
|
||||||
|
`send_mail` lets you email a [meetup group](https://handmadecities.com/meetups) using Handmade Cities branding. You can send an invite to your meetup group like so:
|
||||||
|
|
||||||
|
`> python3 send_mail.py --subject SUBJECT --body BODY`
|
||||||
|
|
||||||
|
where `SUBJECT` is the subject of your email and `BODY` is the file containing its contents. Plain text or HTML is supported. Your email will automatically include the Handmade Cities brand along with unsubscribe links!
|
||||||
|
|
||||||
|
Note that you can dump the mailing list of your meetup group so far:
|
||||||
|
|
||||||
|
`> python3 send_mail.py --dump`
|
||||||
|
|
||||||
|
This list grows automatically as more people sign up for your city.
|
||||||
|
## app.ini
|
||||||
|
`send_mail` requires a companion `app.ini` file. It has the secret credentials to be able to dump the mailing list and otherwise send real emails.
|
||||||
|
|
||||||
|
Below is how the file might look like. (Secret stuff is censored as `xxx`):
|
||||||
|
|
||||||
|
```
|
||||||
|
; User Constants - Update as needed
|
||||||
|
[DEFAULT]
|
||||||
|
LIVE = false
|
||||||
|
TEST_EMAIL = abner@terminal.click
|
||||||
|
SENDER_NAME = Abner Coimbre
|
||||||
|
|
||||||
|
; Handmade Cities Credentials - DON'T TOUCH
|
||||||
|
[hmc]
|
||||||
|
API_URL = https://api.handmadecities.com/v1/meetups/subscribers
|
||||||
|
SHARED_SECRET = xxx
|
||||||
|
CITY = Seattle
|
||||||
|
|
||||||
|
; Postmark App Credentials - NO TOUCHY TOUCHY
|
||||||
|
[postmark]
|
||||||
|
SERVER_TOKEN = xxx
|
||||||
|
API_URL = https://api.postmarkapp.com/email/batchWithTemplates
|
||||||
|
TEMPLATE_ID = xxx
|
||||||
|
SENDER_EMAIL = abner@handmadecities.com
|
||||||
|
MESSAGE_STREAM = xxx
|
||||||
|
```
|
||||||
|
|
||||||
|
`LIVE` is false by default, in which case the script only sends an email to `TEST_EMAIL`. Set `LIVE` to true when you're ready to mass-email your group.
|
||||||
|
## Known Issues
|
||||||
|
`send_mail` uses the `requests` module which may or may not be in your system. You'll need to use `pip` if it's not. See [this issue](https://git.handmadecities.com/meetups/send-mail/issues/2) for details.
|
||||||
58
send_mail.py
58
send_mail.py
@@ -5,6 +5,7 @@
|
|||||||
# ============================ Contributors =========================
|
# ============================ Contributors =========================
|
||||||
# Bug & warning fixes
|
# Bug & warning fixes
|
||||||
# Jacob Bell (@MysteriousJ)
|
# Jacob Bell (@MysteriousJ)
|
||||||
|
# Asaf Gartner
|
||||||
#
|
#
|
||||||
# Emotional Support
|
# Emotional Support
|
||||||
# Cucui Ganon Rosario
|
# Cucui Ganon Rosario
|
||||||
@@ -68,30 +69,39 @@ def sendPostmarkMessage(subject, body, to):
|
|||||||
}
|
}
|
||||||
|
|
||||||
messages = []
|
messages = []
|
||||||
for email in to:
|
|
||||||
message = {
|
# Postmark supports 500 messages per API call.
|
||||||
"From": POSTMARK_SENDER_EMAIL,
|
# Split the 'to' list into chunks of 500 or fewer email addresses
|
||||||
"To": email,
|
for i in range(0, len(to), 500):
|
||||||
"TemplateId": POSTMARK_TEMPLATE_ID,
|
to_chunk = to[i:i+500]
|
||||||
"TemplateModel": {
|
|
||||||
"name": SENDER_NAME,
|
for email in to_chunk:
|
||||||
"email": POSTMARK_SENDER_EMAIL,
|
message = {
|
||||||
"body": body,
|
"From": POSTMARK_SENDER_EMAIL,
|
||||||
"subject": subject
|
"To": email,
|
||||||
},
|
"TemplateId": POSTMARK_TEMPLATE_ID,
|
||||||
"MessageStream": POSTMARK_MESSAGE_STREAM
|
"TemplateModel": {
|
||||||
|
"name": SENDER_NAME,
|
||||||
|
"email": POSTMARK_SENDER_EMAIL,
|
||||||
|
"body": body,
|
||||||
|
"subject": subject
|
||||||
|
},
|
||||||
|
"MessageStream": POSTMARK_MESSAGE_STREAM
|
||||||
|
}
|
||||||
|
messages.append(message)
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"Messages": messages
|
||||||
}
|
}
|
||||||
messages.append(message)
|
|
||||||
|
|
||||||
payload = {
|
# Debug:
|
||||||
"Messages": messages
|
# print(json.dumps(payload, indent=4))
|
||||||
}
|
|
||||||
|
|
||||||
# Debug:
|
result = requests.post(POSTMARK_API_URL, headers=headers, json=payload)
|
||||||
# print(json.dumps(payload, indent=4))
|
print(result.text)
|
||||||
|
|
||||||
result = requests.post(POSTMARK_API_URL, headers=headers, json=payload)
|
# Clear the messages list for the next chunk
|
||||||
print(result.text)
|
messages.clear()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Create a ConfigParser object and read the INI file
|
# Create a ConfigParser object and read the INI file
|
||||||
@@ -127,8 +137,12 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
if args.dump:
|
if args.dump:
|
||||||
meetup_group = dump_emails()
|
meetup_group = dump_emails()
|
||||||
for email in meetup_group:
|
print(f"Handmade Meetups - \033[1m{HMC_CITY}\033[0m\n")
|
||||||
print(email)
|
max_index_width = len(str(len(meetup_group)))
|
||||||
|
for index, email in enumerate(meetup_group, start=1):
|
||||||
|
index_str = str(index).rjust(max_index_width) # Right-align the index
|
||||||
|
print(f"{index_str}. \033[1m{email}\033[0m")
|
||||||
|
print("\nMailing list grows automatically as more subscribe at \033[1mhandmadecities.com/meetups\033[0m")
|
||||||
elif args.subject and args.body:
|
elif args.subject and args.body:
|
||||||
subject = args.subject
|
subject = args.subject
|
||||||
body = ''
|
body = ''
|
||||||
|
|||||||
Reference in New Issue
Block a user