using python with Sendgrid on Heroku - python

I am trying to use Sendgrid to send the email on Heroku, but I get the output that I not seen before. I saw the documentation and it says that the helper library supports few versions of python until 3.8 but mine version is 3.9. Is it this cause me get this error?
**Here is my code: **
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
message = Mail(
from_email='hesheitaliabu#gmail.com',
to_emails='hesheitaliabu#gmail.com',
subject='Sending with Twilio SendGrid is Fun',
html_content='<strong>and easy to do anywhere, even with Python</strong>')
try:
sg = SendGridAPIClient('SG.API_KEY')
response = sg.send(message)
# print(response.status_code)
print(response.body)
print(response.headers)
except Exception as e:
print(e.message)
I get an error:
b''
Server: nginx
Date: Mon, 05 Sep 2022 03:53:19 GMT
Content-Length: 0
Connection: close
X-Message-Id: Y19VjElqRe2byQxJrkJUeg
Access-Control-Allow-Origin: https://sendgrid.api-docs.io
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Authorization, Content-Type, On-behalf-of, x-sg-elas-acl
Access-Control-Max-Age: 600
X-No-CORS-Reason: https://sendgrid.com/docs/Classroom/Basics/API/cors.html
Strict-Transport-Security: max-age=600; includeSubDomains

As we've worked out in the comments, the emails are in fact sending successfully. The message you see logged are the response headers from the API because of these lines:
sg = SendGridAPIClient('SG.API_KEY')
response = sg.send(message)
print(response.body)
print(response.headers)
In this case the message is sent and then the program prints out the response body (which is empty for a successfully sent message) and then the response headers, which you are seeing. This is not an error.
Instead, we have worked out that your email is being sent to the spam inbox.
This is a bit harder to fix as it relies on email inbox providers. However I need to point out one thing that's going to make this very difficult to start with.
Your example shows that you are sending the email from your Gmail address to the same Gmail address. Because of this, Gmail knows it did not send the email from that Gmail address and will instantly treat it as suspicious. You are effectively spoofing your own email address. If you have set up single sender verification with SendGrid for that address, all that does is tell SendGrid that you own the email address and aren't trying to spoof just anyone's email address. This is good for testing that you can use the API to send emails.
However, if you want emails to arrive in inboxes and not the spam inbox then your best bet is to send from a domain that you own that you can authenticate with SendGrid. When you authenticate a domain it sets a number of things like SPF and DKIM that show the inboxes you are sending to that you are the rightful owner of the domain and are authenticated to send emails from the domain. This means you are more likely to arrive in the inbox and not spam.
There is much more to pay attention to to ensure your emails stay out of spam, but in this case, I would start with domain authentication.

Related

How to Send a URL Link within the Text Body with the Twilio API using Python

I am trying to send a text message that contains both text and a hypeprlink but am encountering the following message from the Twilio API:
"Error - 12300 Invalid Content-Type: Attempt to retrieve MediaUrl returned an unsupported Content-Type."
Here is the code I am attempting to leverage:
import os
from twilio.rest import Client
# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ['TWILIO_ACCOUNT_SID']
auth_token = os.environ['TWILIO_AUTH_TOKEN']
client = Client(account_sid, auth_token)
message = client.messages \
.create(
body='Article: https://4r7s.short.gy/GPaoh7',
from_='123-345-5667',
to='123-345-5668',
)
When I send a message without a hyperlink it works fine (e.g. body = 'Here is the article for you to read') but when it contains a link I receive the aforementioned error. I've also tried using a shortened url of the above but that causes the same issue.
I was just able to send messages containing that exact link using my own Twilio account.
There might be an issue in that you are using phone numbers in local format, when they should be provided in e.164 format.
It's possible that your message is being blocked. Certain carriers don't like when you use link shorteners to obscure a link.
The error you are getting definitely seems weird, since you are not sending media. If you continue to have issues with this, I would contact Twilio support.

How to use Mailgun's recipient-variables with Django SMTP mail backend?

How can I properly send batch/bulk/mass emails using MailGun in Django using SMTP protocol?
What I've tried so far?
I am using django.core.mail.backends.smtp.EmailBackend as my EMAIL_BACKEND
and this is the code snippet that I have tried to send the emails.
from django.core.mail import EmailMultiAlternatives
import json
to_emails = [
"mail_1#example.com",
"mail_2#example.com",
"mail_3#example.com",
"mail_4#example.com",
"jerinpetergeorge#gmail.com",
]
mail = EmailMultiAlternatives(
subject="Hey - %recipient.name%",
body="Hey %recipient.name%,\n\nThis is just a batch email test!!!",
from_email="JPG <me#somehost.com>",
to=to_emails,
)
recipient_variables = {
address: {"name": address} for address in to_emails
}
mail.extra_headers["X-Mailgun-Recipient-Variables"] = json.dumps(recipient_variables)
response = mail.send()
print(response)
and I've got the mail as below,
As we can see, the to attribute is filled with all email addresses, which is not what I am expecting.
So, how can I tell the Mailgun/Django to parse my variables properly in order to make the emails looks more personal?
Notes
I prefer to use SMTP protocol
I've tried the REST APIs of Mailgun and it was a success (but, I prefer SMTP)
I found django-anymail and seems it has the feature. But, It also uses the APIs (correct me if I am wrong)
Update-1
Updated the to argument to to="%recipient%" But, got
TypeError: "to" argument must be a list or tuple
Updated the to argument to to=["%recipient%"] But, got
smtplib.SMTPRecipientsRefused: {'=?utf-8?q?=25recipient=25?=': (501, b'Invalid command or cannot parse to address')}
As we can see, the to attribute is filled with all email addresses, which is not what I am expecting.
It is not properly supported with SMTP by Mailgun.
However, relying on the (unintuitive) implementation of BCC in Mailgun, there is a workaround:
mail = EmailMultiAlternatives(
subject="Hey - %recipient.name%",
body="Hey %recipient.name%,\n\nThis is just a batch email test!!!",
from_email="JPG <me#somehost.com>",
# to=to_emails, # Replace this
bcc=to_emails, # with this
)
recipient_variables = {
address: {"name": address} for address in to_emails
}
mail.extra_headers["To"] = "%recipient%" # Add this
mail.extra_headers["X-Mailgun-Recipient-Variables"] = json.dumps(recipient_variables)
Reference: https://stackoverflow.com/questions/37948729/mailgun-smtp-batch-sending-with-recipient-variables-shows-all-recipients-in-to-field
Why does to=["%recipient%"] not work with SMTP?
It's the standard in the protocol.
From https://documentation.mailgun.com/_/downloads/en/latest/pdf/:
SMTP send will error with “cannot parse to address” or “cannot parse from address” if the provided email address fails syntax checks in accordance with RFC5321, RFC5322, RFC6854.
What to do for proper support of Batch Sending with Mailgun?
Use the API.
From https://stackoverflow.com/questions/30787399/laravel-5-sending-group-emails (multiposted to https://laracasts.com/discuss/channels/laravel/sending-email-to-1000s-of-reciepents):
So far, I have created an array of recipient email addresses, sent the email to a webmaster type address, and included the end recipients in BCC
While this works, it's not ideal.
Rather than using Laravel's built in Mail, I elected to use Mailgun's API (specifically batch sending) directly
This also allows me to access unique recipient variables within my email template
(It's not specific to Laravel/PHP, but to SMTP via Mailgun.)
What do you mean by "unintuitive" implementation of BCC in Mailgun?
Mailgun effectively personalises the email for each BCC recipient using recipient-variables.
From https://github.com/mailgun/mailgun-js-boland/issues/89:
the bcc person is receiving the email as it was addressed to them instead of being part of the bcc
This causes a separate issue when you actually want BCC recipients to get the same content.
From https://stackoverflow.com/questions/48887866/bcc-in-mailgun-batch-send-does-not-include-substitutions:
In the copy sent to the bcc address, the recip_vars substitution has not been made.
According to the good people at Mailgun, this is not possible, at least in the current release of the service.

flask_mail I get TWO different FROM lines mail header

I'm using flask_mail configured to use gmail smtp server. It sends mail fine except all mail looks it is coming from the gmail smtp user name and NOT from what I set in the 'sender' argument of the mail.send_message(...) command. When I look at the source of the generate emails I see 2 different FROM addresses. How can I change this to show my desired 'from'?
mail.send_message(subject='subject line',
sender='my_from_email#gmail.com',
recipients=['my_to_email#gmail.com'],
bcc=['bcc_email#gmail.com'],
reply_to='my_from_email#gmail.com')
snip-it of header looks like...
...
From: my_smtp_user_name#gmail.com
X-Google-Original-From: my_from_email#gmail.com
Content-Type: multipart/mixed; boundary="===============8405132704319078372=="
MIME-Version: 1.0
...
TLDR: gmail smtp server is preventing email spoofing.
see: https://github.com/gophish/gophish/issues/1311
to fix:
log into your my_smtp_user_name#gmail.com account in Gmail and set up sending email as my_from_email#gmail.com there first. Once your account is allowed and authenticated as allowed to send email as your other account your headers should stop being re-writen.
see : https://support.google.com/mail/answer/22370?hl=en

Trying to spoof an email address

I'm sure this has been asked, but I can't find anything to get mine to work.
I'm trying to send follow up emails to clients, but I want to spoof the email address so the from address is for my coworker. I read somewhere online that the from address in the header is simply a text field that can be edited, but I still cannot send the email.
import smtplib
email_to = '*****#gmail.com'
username = '*******#outlook.com'
password = '*********'
other_email = '*******#outlook.com'
mail = smtplib.SMTP('Outlook.com', 25)
mail.ehlo()
mail.starttls()
mail.login(username,password)
header = ('To:' + email_to + '\n' +'From: ' + other_email + '\n'
+ 'Subject: Python Project Test\n')
message = (header +
'\n\n This is a test message generated from a Python script. \n\n')
mail.sendmail(username, email_to, message)
mail.close()
print("Email sent successfully.")
I know this can be done, but can someone point me in the right direction? Is there any way for me to disguise my name in the from field as that of the email that is supposed to get this?
===================================
Also, for the sake of completion, here is the error I got:
Traceback (most recent call last):
File "C:\Users\*****\Desktop\email outlook.py", line 16, in <module>
mail.sendmail(username, email_to, message)
File "C:\Users\*****\AppData\Local\Programs\Python\Python36-32\lib\smtplib.py", line 887, in sendmail
raise SMTPDataError(code, resp)
smtplib.SMTPDataError: (550, b'5.7.60 SMTP; Client does not have permissions to send as this sender')
I was hoping if there was a way to make the other_name an alias of the username.
The very short version: This isn't going to work.
Once upon a time, it was reasonably possible to do what you are asking to do. In the old days, when the internet was small and spam did not exist, the receiving server would just trust you. You could just connect to mail.example.com and say you were sending on behalf of someone#example.org, and example.com would just believe you.
But those days are over and done with. Nowadays, SMTP servers are a lot less trusting. So let's go through the problems with your approach:
You are trying to route your email through outlook.com. outlook.com knows perfectly well that you are username and not other_email. If you want to send email as other_email, you need to authenticate as other_email.
You could connect directly to gmail.com, claim to be outlook.com, and try to send the email that way. But Gmail knows you're not outlook.com, because you're missing these things. So it will likely flag your message as spam, bounce it, or even* accept it and then discard it entirely.
You could fix (1) by changing your code, but because of (2), there's little point.
* I do not work on the Gmail team. I am guessing how Gmail would respond to this based solely on public information about how modern email servers are typically configured. YMMV.

Can I get the incoming message by using Mailgun?

A use Mailgun to send b a email, after b receive the email and reply to a.If I want to track the email coming from b, How I can get the email?
Here is the code:
1.sendmail.py
from smtplib import SMTP
import requests
login_name = "postmaster#zzb.mailgun.org"
password = "********"
def send_message_via_smtp():
smtp = SMTP("smtp.mailgun.org", 587)
smtp.login(login_name, password)
smtp.sendmail("zebozhuang#163.com","348284770#qq.com", "Subject:mailgun test \n\n just for test.\n\n")
smtp.quit()
if __name__=="__main__":
send_message_via_smtp()
2.create_route.py
import requests
from werkzeug.datastructures import MultiDict
def create_route():
return requests.post(
"https://api.mailgun.net/v2/routes",
auth=("api", "key-9c4-t2q6fouilngjummvtv1rge7t00f2"),
data=MultiDict([("priority", 1),
("description", "Sample route"),
("expression", "match_recipient('.*#qq.com')"),
("action", "forward('qiyazhuang#gmail.com')"),
("action", "stop()")])
)
I create the route and I run the script sendmail.py.After someone who use email 348284770#qq.com reply to the other who use email zebozhuang#163.com, the Gmail
can not receive the message by using the Mailgun method 'forward'.
Could anyone tell me why?
Your messages are likely being delivered. Check the "Logs" tab of the Mailgun Control Panel.
Do you see any entries that look like this:
Routed: .*#qq.com -> qiyazhuang#gmail.com 'SUBJECT HERE'
The "Routed" prefix means that the message triggered a Route. If you're seeing this, and the next log entry is prefixed with "Delivered", the message is likely being delivered to Gmail without issue. Check your Gmail spam folder if you still don't see the messages in the inbox folder.
Disclaimer: I work for Mailgun Support. :)

Categories