flask mail error “SMTPServerDisconnected('please run connect() first')” - python-3.x

I am writing a little web application based on Miguel Grinberg's Flasky. I use the exact same code for user send reset password mail using gmail.
The following as my email.py file here i can implement mail sending function
def send_password_reset_email(user):
token = user.get_reset_password_token()
send_email(_('[Microblog] Reset Your Password'),
sender=current_app.config['ADMINS'][0],
recipients=[user.email],
text_body=render_template('email/reset_password.txt',
user=user, token=token),
html_body=render_template('email/reset_password.html',
user=user, token=token))
def send_async_email(app, msg):
with app.app_context():
mail.send(msg)
def send_email(subject, sender, recipients, text_body, html_body):
msg = Message(subject, sender=sender, recipients=recipients)
msg.body = text_body
msg.html = html_body
Thread(target=send_async_email,
args=(current_app._get_current_object(), msg)).start()
In routes.py file im getting email from the user and if the user email match then i well send the token to the user via mail
#bp.route('/reset_password_request', methods=['GET', 'POST'])
def reset_password_request():
if current_user.is_authenticated:
return redirect(url_for('main.index'))
form = ResetPasswordRequestForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user:
send_password_reset_email(user)
flash(
_('Check your email for the instructions to reset your password'))
return redirect(url_for('auth.login'))
return render_template('auth/reset_password_request.html',
title=_('Reset Password'), form=form)
#bp.route('/reset_password/<token>', methods=['GET', 'POST'])
def reset_password(token):
if current_user.is_authenticated:
return redirect(url_for('main.index'))
user = User.verify_reset_password_token(token)
if not user:
return redirect(url_for('main.index'))
form = ResetPasswordForm()
if form.validate_on_submit():
user.set_password(form.password.data)
db.session.commit()
flash(_('Your password has been reset.'))
return redirect(url_for('auth.login'))
return render_template('auth/reset_password.html', form=form)
In model.py file in the user model i generate a token for a user and also check the user token
def get_reset_password_token(self, expires_in=600):
return jwt.encode(
{'reset_password': self.id, 'exp': time() + expires_in},
current_app.config['SECRET_KEY'],
algorithm='HS256').decode('utf-8')
#staticmethod
def varify_reset_password_token(token):
try:
id = jwt.decode(token, current_app.config['SECRET_KEY'],
algorithms=['HS256'])['reset_password']
except:
return
return User.query.get(id)
my flask mail setup is as follows config.py file
MAIL_SERVER = os.environ.get('MAIL_SERVER')
MAIL_PORT = int(os.environ.get('MAIL_PORT') or 25)
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS') is not None
MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
ADMINS =['socialtraffic#gmail.com']
The following Error i get in the terminal
Traceback (most recent call last):
File "c:\python38\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "c:\python38\lib\threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\Ijaz Bacha\project\microblog1\app\email.py", line 9, in send_async_email
mail.send(msg)
File "c:\users\ijaz bacha\project\microblog1\venv\lib\site-packages\flask_mail.py", line 492, in send
message.send(connection)
File "c:\users\ijaz bacha\project\microblog1\venv\lib\site-packages\flask_mail.py", line 152, in __exit__
self.host.quit()
File "c:\python38\lib\smtplib.py", line 988, in quit
res = self.docmd("quit")
File "c:\python38\lib\smtplib.py", line 424, in docmd
self.putcmd(cmd, args)
File "c:\python38\lib\smtplib.py", line 371, in putcmd
self.send(str)
File "c:\python38\lib\smtplib.py", line 363, in send
raise SMTPServerDisconnected('please run connect() first')
smtplib.SMTPServerDisconnected: please run connect() first

I am also doing the same tutorial and ran into the same problem. I found the answer on Miguel's Blog:
You need two terminal windows.
The first terminal running your local mail server that emulates your emails being sent:
$(venv) python -m smtpd -n -c DebuggingServer localhost:8025
Your main flask terminal window with the following required commands (FLASK_DEBUG=1 is optional but highly recommended for troubleshooting):
$ export FLASK_APP=microblog.py
$ export FLASK_DEBUG=1
$ export MAIL_SERVER=localhost
$ export MAIL_PORT=8025
$ flask run
This solved my problems.

In my experience, a while ago I had a very similar issue that you you were having. After troubleshooting, I found out that my code worked when I would create a mail class, and call function like $mailclass.ehlo etc.
Based on the error its having an issue connecting or staying connected. Try calling the connect methods in the function itself and close of the connection after each email.

I decided to change the following line in the app/__init__.py file:
mail = Mail(app)
with:
mail = Mail()
mail.init_app(app)
Solved the issue for me

Related

Youtube data api error when changing video title

why did i get this error on the script given below:
Traceback (most recent call last):
File "C:\Path\YoutubeApi\main.py", line 54, in <module>
main()
File "C:\Path\YoutubeApi\main.py", line 49, in main
response = request.execute()
File "C:\Users\$user\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\googleapiclient\_helpers.py", line 131, in positional_wrapper
return wrapped(*args, **kwargs)
File "C:\Users\$user\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\LocalCache\local-packages\Python39\site-packages\googleapiclient\http.py", line 937, in execute
raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 400 when requesting https://youtube.googleapis.com/youtube/v3/videos?part=snippet&alt=json returned "The <code>snippet.categoryId</code> property specifies an invalid category ID. Use the <code>videoCategories.list</code> method to retrieve supported categories.". Details: "[{'message': 'The <code>snippet.categoryId</code> property specifies an invalid category ID. Use the <code>videoCategories.list</code> method to retrieve supported categories.', 'domain': 'youtube.video', 'reason': 'invalidCategoryId', 'location': 'body.snippet.categoryId', 'locationType': 'other'}]">
Main.py
import os
import pickle
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
def main():
credentials = None
# token.pickle stores the user's credentials from previously successful logins
if os.path.exists('token.pickle'):
print('Loading Credentials From File...')
with open('token.pickle', 'rb') as token:
credentials = pickle.load(token)
if not credentials or not credentials.valid:
if credentials and credentials.expired and credentials.refresh_token:
print('Refreshing Access Token...')
credentials.refresh(Request())
else:
print('Fetching New Tokens...')
flow = InstalledAppFlow.from_client_secrets_file(
'client_secrets.json',
scopes=[
'https://www.googleapis.com/auth/youtube.force-ssl'
]
)
flow.run_local_server(port=8080, prompt='consent',
authorization_prompt_message='')
credentials = flow.credentials
# Save the credentials for the next run
with open('token.pickle', 'wb') as f:
print('Saving Credentials for Future Use...')
pickle.dump(credentials, f)
youtube = build('youtube','v3',credentials=credentials)
request = youtube.videos().update(
part = 'snippet',
body={
"id": "OSxK-tscmVA",
"snippet":{
"title":"It's changed",
}
}
)
response = request.execute()
print(response)
if __name__ == '__main__':
main()
Script Explanation:
What the script does is that if there's no file named token.pickle it will ask the user to authorize the application and the script will store the user credentials in token.pickle file so that the user doesn't have to authorize the application on every single run and the part 2 of the script changes my YouTube video's title.
Unfortunately, you seem not inclined to make use of the official specification of the Videos.update API endpoint:
The request body of your call to the endpoint needs to specify the video category ID too for to be accepted by the API back-end.
Note that the update_video.py sample code from Google -- that I indicated you at the beginning of your series of posts as valuable source of information -- has all these required things in it.
Again, please acknowledge that you have to absorb (i.e. understand) that code. There's no other way than going through reading carefully the official documentation.

Message in a specific Discord channel

Hi guys i'm trying to make the bot send a message automatically in a specific channel. I took the channel ID and pass it in the if condition (a_string.find ('data: []')! = -1). However this code gives me this error. See OUTPU ERROR.
P.S. I'm using Replit and Live is the file name (Live.py)
from discord.ext import commands
from Naked.toolshed.shell import execute_js, muterun_js
import sys
class Live(commands.Cog):
def __init__(self,client):
self.client=client
#commands.Cog.listener()
async def on_ready(self):
channel = self.get_channel(828711580434169858)
response = muterun_js('serverJs.js')
original_stdout = sys.stdout # Save a reference to the original standard output
if response.exitcode == 0:
a_string= str(response.stdout)#stampa in console
if (a_string.find('data: []') != -1):
print("Streamer: Offline ")
else:
print("Streamer: Online")
await channel.send('Live Link: https://...link....')
else:
sys.stderr.write(response.stderr)
#commands.command()
async def Live(self,ctx):
await ctx.send('')
def setup(client):
client.add_cog(Live(client))
OUTPUT ERROR:
Ignoring exception in on_ready
Traceback (most recent call last):
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "/home/runner/Solaris-IA/cogs/Live.py", line 12, in on_ready
channel = self.get_channel(828711580434169858)
AttributeError: 'Live' object has no attribute 'get_channel'
It's self.client.get_channel, not self.get_channel, you haven't defined that function
channel = self.client.get_channel(828711580434169858)

Python3 Slack RTMClient in not working behind proxy

I am trying to create a simple Python bot for my project. Everything is working fine on my localhost, but the same code stops working behind the network firewall which needs environment proxy to be set.
from slack import RTMClient
proxy='http://XXXX:NNNN'
token='XXXX'
class Botso():
def __init__(self):
self.proxy=self.get_proxy()
self.rt= RTMClient(
token=token,
connect_method='rtm.start',
proxy=self.proxy
)
def get_proxy(self):
host=socket.gethostname()
if "internal" in host:
return None
elif "XXX" in host:
return proxy
#RTMClient.run_on(event="message")
def say_hello(**payload):
data = payload['data']
web_client = payload['web_client']
if 'text' in data and 'hii' in data['text']:
channel_id = data['channel']
thread_ts = data['ts']
user = data['user'] # This is not username but user ID (the format is either U*** or W***)
web_client.chat_postMessage(
channel=channel_id,
text=f"Hi <#{user}>!"
#thread_ts=thread_ts
)
if __name__ == '__main__':
botso=Botso()
botso.rt.start()
The error I am getting while initializing the RTMClient is
Traceback (most recent call last):
File "botso.py" , in <module>
botso.rt.start()
File "/usr/lib64/python3.6/http/client.py", line 974, in send
self.connect()
File "/usr/lib64/python3.6/http/client.py", line 1407, in connect
super().connect()
File "/usr/lib64/python3.6/http/client.py", line 950, in connect
self._tunnel()
File "/usr/lib64/python3.6/http/client.py", line 929, in _tunnel
message.strip()))
OSError: Tunnel connection failed: 403 Forbidden
I have other code in the same environment which uses the same proxy to send slack messages and works fine bu using request api.
params={
'token': self.slack_token,
'types': ['public_channel','private_channel']
}
slack_url='https://slack.com/api/conversations.list'
response = requests.get(url=slack_url,params=params,proxies=self.proxy).json()
How can we make the RTMClient work with proxy and Python3.
Couldn't find much help in slack API documents.

Issue when trying to send emails through Python

OS: MacCatalinva V10.15.3
Python: 3.7.7
PiP: 20.0.2
Hey,
I'm new to coding so I'm not sure what this really means.
I'm trying to send emails via Python through Gmail, I've set my account to accept "Less secure app access" and followed the steps in this guide, but all I get is the following:
`[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1076)
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 354, in send
self.sock.sendall(s)
OSError: [Errno 9] Bad file descriptor
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/mymac/Desktop/Test2.py", line 34, in
server.quit()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 984, in quit
res = self.docmd("quit")
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 420, in docmd
self.putcmd(cmd, args)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 367, in putcmd
self.send(str)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/smtplib.py", line 357, in send
raise SMTPServerDisconnected('Server not connected')
smtplib.SMTPServerDisconnected: Server not connected`
And this is my Code:
import smtplib
import ssl
sender_email = "myemailadress#gmail.com"
receiver_email = "myadress#hotmail.com"
message = """\
Subject: Hi there
This message is sent from Python."""
# Send email here
smtp_server = "smtp.gmail.com"
port = 587 # For starttls
sender_email = "myemailadress#gmail.com"
password = input("Type your password and press enter: ")
# Create a secure SSL context
context = ssl.create_default_context()
# Try to log in to server and send email
try:
server = smtplib.SMTP(smtp_server, port)
server.ehlo() # Can be omitted
server.starttls(context=context) # Secure the connection
server.ehlo() # Can be omitted
server.login(sender_email, password)
# TODO: Send email here
except Exception as e:
# Print any error messages to stdout
print(e)
finally:
server.quit()
1)After this line:
server.login(sender_email, password)
make sure to send the message you have it.
For that:
server.sendmail(sender_email,receiver_email,message)
that's it, I hope.

Sending my first message on the slack API

I registered my first app, and it looks like this:
All of the fields are populated below the screen shot.
Now, I have some basic python code using the examples found on their repo.
I create the following test script:
import traceback
app_id = 'FAKE.VALUE'
client_id = 'FAKE.VALUE'
client_secret = 'FAKE.VALUE'
signin_secret = 'FAKE.VALUE'
verification_token = 'FAKE.VALUE'
items = locals()
import os
import slack
items = locals().copy()
for k in items:
if '__' not in k:
val = items[k]
try:
client = slack.WebClient(token=val)
response = client.chat_postMessage(
channel='CE476K9HT',
text='Hello-----' + str(val))
print(response)
except:
print(k)
traceback.print_exc()
print('-'*50)
But all of the responses I get say:
The server responses with: {'ok':False,'error':'invalid_auth'}
For some reason, is it necessary to use path variables?
It is unclear to me what type of auth is required here.
After doing what Erik suggested,
I have a xoxp code and registered the redirect url to http://localhost.
and added the following scopes:
and updated my code to look like:
oauth_token ='xoxp-*****************'
import os
import slack
items = locals().copy()
client = slack.WebClient(token=oauth_token)
response = client.chat_postMessage(
channel='my_channel_id',
text='Hello-----')
I got my channel ID from the url:
https://app.slack.com/client/FOO/my_channel_id
When I run my code, I get the following back:
Traceback (most recent call last):
File "/home/usr/git/slack_messaging/slack_messaging.py", line 20, in <module>
text='Hello-----')
File "/home/usr/git/python-slackclient/slack/web/client.py", line 382, in chat_postMessage
return self.api_call("chat.postMessage", json=kwargs)
File "/home/usr/git/python-slackclient/slack/web/base_client.py", line 172, in api_call
return self._event_loop.run_until_complete(future)
File "/home/usr/anaconda2/envs/beer/lib/python3.7/asyncio/base_events.py", line 573, in run_until_complete
return future.result()
File "/home/usr/git/python-slackclient/slack/web/base_client.py", line 241, in _send
return SlackResponse(**{**data, **res}).validate()
File "/home/usr/git/python-slackclient/slack/web/slack_response.py", line 176, in validate
raise e.SlackApiError(message=msg, response=self)
slack.errors.SlackApiError: The request to the Slack API failed.
The server responded with: {'ok': False, 'error': 'missing_scope', 'needed': 'chat:write:user', 'provided': 'admin,identify'}
Process finished with exit code 1
You need two things to make your script work.
1. OAuth token
You need a valid OAuth token and provide it when initializing the Slack Client:
client = slack.WebClient(token="xoxb-xxx")
To get a token you need to install your Slack app to a workspace. You can do that on the app management page under "Install App". Your OAuth token will also be displayed on that page once you installed it.
2. Permissions
Your Oauth Token / Slack app needs to have the permission to post messages. On the app management pages go to "OAuth & permission" and add the needed permission to your app:. e.g. chat:write:user for user tokens.
Note that you need to reinstall your app every time to add a permission.

Resources