How to fix error : no module named sendgrid when try to use sendgrid python lib in PHP.


"no module named sendgrid" error reported with below codes:

<?php
system("/usr/bin/python sendmail.py 2>&1");
system("/usr/bin/python --version 2>&1", $ret);
?>

sendmail.py

import sendgrid
import os
from sendgrid.helpers.mail import *

sg = sendgrid.SendGridAPIClient(apikey=os.environ.get('SENDGRID_API_KEY'))
from_email = Email("test@example.com")
to_email = Email("test@example.com")
subject = "Sending with SendGrid is Fun"
content = Content("text/plain", "and easy to do anywhere, even with Python")
mail = Mail(from_email, subject, to_email, content)
response = sg.client.mail.send.post(request_body=mail.get())
print(response.status_code)
print(response.body)
print(response.headers)
....




nginx config your websites' favicon

        1. vim nginx.conf
        # set site favicon
        location /favicon.ico {
            root html;
        }

       2. place a favicon.ico file under html/

       3. optional, add below codes to your index.html.
<link rel="icon" href="/favicon.ico" mce_href="/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="/favicon.ico" mce_href="/favicon.ico" type="image/x-icon">    



        # set site favicon
        location /favicon.ico {
            root html;
        }

How to extend file extensions to be parsed by PHP

sudo vim /etc/php/7.0/fpm/pool.d/www.confsudo vim /etc/php/7.0/fpm/pool.d/www.conf
By default, PHP only parse files with .php extension.
We can extend extensions with security.limit_extensions directive.

sudo vim /etc/php/7.0/fpm/pool.d/www.conf
sudo vim /etc/php/7.0/fpm/pool.d/www.conf
; Limits the extensions of the main script FPM will allow to parse. This can
; prevent configuration mistakes on the web server side. You should only limit
; FPM to .php extensions to prevent malicious users to use other extensions to
; exectute php code.
; Note: set an empty value to allow all extensions.
; Default Value: .php
; You can add any extensions you want to be parsed as php
security.limit_extensions = .php .php3 .php4 .php5 .php7 .ler

sudo service php7.0-fpm restart

Config nginx:

/etc/nginx/nginx.conf
        location ~ \.(php|ler)$ {
            include fastcgi.conf;
            fastcgi_pass   unix:/run/php/php7.0-fpm.sock;
        }

        location ~ \.(php|ler)$ {
            root vhosts/$root_name;
            include fastcgi.conf;
            fastcgi_pass   unix:/run/php/php7.0-fpm.sock;
        }
sudo service php7.0-fpm restart 

sudo service nginx restart

Let's do the test.

cat index.ler<?php
phpinfo();
?>
.ler parsed as .php too, works well.

How to set up LNMP(linux+nginx+mysql+php) developer tool on your ubuntu server

Install all software:
sudo apt-get install nginx
sudo apt-get install php7.0-fpm
sudo apt-get install php7.0-curl
sudo apt-get install php7.0-gd php7.0-mcrypt php7.0-mysql
sudo apt-get install mysql-server mysql-client

Please remember your mysql database root password!!!

Let's config up.

1. Add nginx user and group, nginx server and php-fpm will run as nginx user.
sudo groupadd nginx 
sudo groupadd nginx
sudo useradd -g nginx nginx
sudo service php7.0-fpm restart

2. Config php-fpm
/etc/php/7.0/fpm/php.ini
cgi.fix_pathinfo=0

/etc/php/7.0/fpm/pool.d/www.conf
listen = /run/php/php7.0-fpm.sock
listen.owner = nginx
listen.group = nginx

sudo service php7.0-fpm restart

3. Config nginx
/etc/nginx/nginx.conf
user nginx nginx;
location ~ \.php$ {
    include fastcgi.conf;
    fastcgi_pass   unix:/run/php/php7.0-fpm.sock;
}

sudo service nginx restart

PS:keep the user/group of php-fpm same as nginx server, I have marked as blue nginx above.


And it should not the same user that owns your virtual host directory for better security.
My websites are in vhosts folder, the user/group are errong_leng.
drwxrwxr-x  4 errong_leng errong_leng 4096 May 19 09:11 vhosts

Ok. let's do the test.
cat index.php
<?php
phpinfo();
?>

Everything looks fine.




cat index.php 
<?php
phpinfo();
?>
drwxrwxr-x  4 errong_leng errong_leng 4096 May 19 09:11 vhosts
drwxrwxr-x  4 errong_leng errong_leng 4096 May 19 09:11 vhosts
drwxrwxr-x  4 errong_leng errong_leng 4096 May 19 09:11 vhosts
drwxrwxr-x  4 errong_leng errong_leng 4096 May 19 09:11 vhosts

Send email with attachments on your google compute engine via sendgrid-python

precondition:
  1. Use the Google Cloud Launcher to sign up for the SendGrid Email service. Make a note of your SendGrid SMTP account credentials, which include username, password, and hostname. Your SMTP username and password are the same as what you used to sign up for the service. The SendGrid hostname is smtp.sendgrid.net.
  2. Create an API key:
    1. Sign in to Sendgrid and go to Settings > API Keys.
    2. Create an API key.
    3. Select the permissions for the key. At a minimum, the key will need Mail send permissions to send email.
    4. Click Save to create the key.
    5. SendGrid generates a new key. This is the only copy of the key so make sure to copy the key and save it for later.


 
Please remember your key and save it somewhere safe.
 
OK. Now we can use sendgrid python library to send email.
Of cause, you can still follow offical help to use sendgrid with other solution.
https://cloud.google.com/compute/docs/tutorials/sending-mail/using-sendgrid

install sendgrid-python 
$pip install sendgrid
 
Sample python codes:
errong_leng@blogvpn:~/algo$ cat sendmail.py
import base64
import getopt
import mimetypes
import os
import sendgrid
import sys
from sendgrid.helpers.mail import *

def useage():
    print ("python sendmail.py [-s subject] [-a attachment ] [-c cc-addr] [-b bcc-addr] [-f from-addr] [-t to-addr] to-addr . . .")
    sys.exit()

opts, args = getopt.getopt(sys.argv[1:], "ha:b:c:f:s:t:")

attachs = []
cc = []
bc = []
tc = []
from_addr = ''
subject = ''

for op, value in opts:
  if op == "-h":
      useage()
  elif op == "-a":
      attachs.append(value)
  elif op == "-b":
      bc.append(value)
  elif op == "-c":
      cc.append(value)
  elif op == "-s":
      subject = value
  elif op == "-f":
      from_addr = value
  elif op == "-t":
      tc.append(value)

if (len(args) <= 0):
    useage()

sg = sendgrid.SendGridAPIClient(apikey='REPLACEWITHYOURAPIKEY')
mail = Mail()
mail.from_email = (Email(from_addr))
mail.subject = subject
personalization = Personalization()
personalization.add_to(Email(args[0]))
for tcs in tc:
    personalization.add_to(Email(tcs))
for ccs in cc:
    personalization.add_cc(Email(ccs))
for bcc in bc:
    personalization.add_bcc(Email(bcc))
personalization.subject = subject
mail.add_personalization(personalization)

contents = args[1:]
for ct in contents:
    if (len(ct) > 0):
        mail.add_content(Content("text/plain", ct))
      
for af in attachs:
    data = ''
    with open(af, 'rb') as f:
        data = f.read()
        f.close()
    if (len(data) > 0):
        adata = base64.b64encode(data)
        attachment = Attachment()
        attachment.content = adata
        s = os.path.split(af)
        attachment.filename = s[len(s)-1]
        attachment.type = mimetypes.guess_type(attachment.filename)[0]
        attachment.disposition = "attachment"
        attachment.content_id = af
        mail.add_attachment(attachment)

response = sg.client.mail.send.post(request_body=mail.get())

print(response.status_code)
print(response.body)
print(response.headers)            
 
 
errong_leng@blogvpn:~/algo$ python sendmail.py -t "errong.leng@abc.com" -s 
"Hello" -f "errong.leng@gmail.com" -c "errong.leng@hotmail.com" 
-b "errong.leng@samsung.com" -a configs/104.199.178.17/zqzz.p12 
-a configs/104.199.178.17/zqzz.mobileconfig 
errong.leng@gmail.com "Hello with content and attachment" 
 
202

Server: nginx
Date: Fri, 19 May 2017 04:04:45 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 0
Connection: close
X-Message-Id: x7xHfWk8SmWlxUe6Ew6tmA
X-Frame-Options: DENY
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
 
Once you see 202, which means email sending successfully. 
 
 
 

神先爱了我们



当那日,我必为我的民,与田野的走兽和空中的飞鸟,并地上的昆虫立约;又必在国中折断弓刀,止息争战,使他们安然躺卧。  (何西阿书 2:18 和合本)
In that day I will make a covenant for them with the beasts of the field, the birds in the sky and the creatures that move along the ground. Bow and sword and battle I will abolish from the land, so that all may lie down in safety.  (Hosea 2:18 NIV)
我必聘你永远归我为妻,以仁义、公平、慈爱、怜悯聘你归我;  (何西阿书 2:19 和合本)
I will betroth you to me forever; I will betroth you in righteousness and justice, in love and compassion.  (Hosea 2:19 NIV)
也以诚实聘你归我,你就必认识我—耶和华。 (何西阿书 2:20 和合本)
I will betroth you in faithfulness, and you will acknowledge the Lord .  (Hosea 2:20 NIV)
耶和华说:那日我必应允,我必应允天,天必应允地; (何西阿书 2:21 和合本)
“In that day I will respond,” declares the Lord — “I will respond to the skies, and they will respond to the earth;  (Hosea 2:21 NIV)
地必应允五谷、新酒,和油,这些必应允耶斯列民(耶斯列就是 神栽种的意思) 。 (何西阿书 2:22 和合本)
and the earth will respond to the grain, the new wine and the olive oil, and they will respond to Jezreel.  (Hosea 2:22 NIV)
我必将她种在这地。素不蒙怜悯的,我必怜悯;本非我民的,我必对他说:你是我的民;他必说:你是我的 神。” (何西阿书 2:23 和合本)
I will plant her for myself in the land; I will show my love to the one I called ‘Not my loved one. ’ I will say to those called ‘Not my people, ’ ‘You are my people’; and they will say, ‘You are my God.’ ”  (Hosea 2:23 NIV)


The best way to force http request redirect to https in nginx

Use 301 redirect.
 
    server {
        listen  80;
        server_name blog.errong.win;
        return 301 https://$server_name$request_uri;
    }

    server {
        listen  80;
        server_name freevpn.errong.win;
        return 301 https://$server_name$request_uri;
    }

    server {
        listen  80;
        server_name www.errong.win errong.win;
        return 301 https://$server_name$request_uri;
    }

    server {
        listen       443 ssl;

        ssl_certificate      /etc/letsencrypt/live/errong.win/fullchain.pem;
        ssl_certificate_key  /etc/letsencrypt/live/errong.win/privkey.pem;

        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;

        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;

        server_name  ~^(.+)?\.errong\.win$;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   vhosts/$1;
            index  index.html index.htm;
        }
   } 
 
Remember reload your nginx server 
sudo sbin/nginx -s reload 

You can check with developer tool:
 

fixed: embedded-redis: Unable to run on macOS Sonoma

Issue you might see below error while trying to run embedded-redis for your testing on your macOS after you upgrade to Sonoma. java.la...