Help with sending mail from Python application

12 views
Skip to first unread message

Alexei Karpov

unread,
Mar 28, 2024, 12:36:11 AMMar 28
to sandst...@googlegroups.com

Dear all, good day.

I would be very grateful if someone can give me some pointers.

I am trying to send a test email from this app via python/capnpn.

I have created a send mail as per the sandstorm documentation which looks something like this:

import socket
import capnp
import sandstorm_http_bridge_capnp
import hack_session_capnp

def send_email(session_id, submission_details):
    try:
        s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        s.connect("/tmp/sandstorm-api")

        client = capnp.TwoPartyClient(s)
        bridge = client.ez_restore().cast_as(sandstorm_http_bridge_capnp.SandstormHttpBridge)
        session_context = bridge.get_session_context({"id": session_id}).wait().context
        email_cap = session_context.cast_as(hack_session_capnp.HackSessionContext)

        req = email_cap.send_request()
        email = req.email

        setattr(email, 'from', email_cap.getUserAddress().wait())
        email.to = ['a...@hrbr.life']
        email.subject = 'New Submission'
        email.text = f"New submission received: {submission_details}"

        req.send().wait()
        print("Email sent successfully.")
    except Exception as e:
        print(f"Failed to send email: {e}", exc_info=True)


I have also tried to initiate capnp in my app by starting it with the following:

import os
import socket
import capnp
from flask import Flask, render_template, request, redirect, url_for, flash
from werkzeug.utils import secure_filename
import hashlib
from extensions import db
from models import Submission


# Initialize Cap'n Proto event loop for Sandstorm
capnp.remove_event_loop()
capnp.create_event_loop(threaded=True)

# Load the relevant interface descriptors from the current sandstorm bundle.
bridge = capnp.load("/opt/sandstorm/latest/usr/include/sandstorm/sandstorm-http-bridge.capnp",
            imports=[
                "/opt/sandstorm/latest/usr/include",
            ]
        )
util = capnp.load("/opt/sandstorm/latest/usr/include/sandstorm/util.capnp",
            imports=[
                "/opt/sandstorm/latest/usr/include",
            ]
        )

powerbox = capnp.load("/opt/sandstorm/latest/usr/include/sandstorm/powerbox.capnp",
            imports=[
                "/opt/sandstorm/latest/usr/include",
            ]
        )

identity = capnp.load("/opt/sandstorm/latest/usr/include/sandstorm/identity.capnp",
            imports=[
                "/opt/sandstorm/latest/usr/include",
            ]
        )

grain = capnp.load("/opt/sandstorm/latest/usr/include/sandstorm/grain.capnp",
            imports=[
                "/opt/sandstorm/latest/usr/include",
            ]
        )

hack_session = capnp.load("/opt/sandstorm/latest/usr/include/sandstorm/hack-session.capnp",
            imports=[
                "/opt/sandstorm/latest/usr/include",
            ]
        )

pkgdef = capnp.load("/sandstorm-pkgdef.capnp",
            imports=[
                "/opt/sandstorm/latest/usr/include",
            ]
        )

capnpip = capnp.load("/opt/sandstorm/latest/usr/include/sandstorm/ip.capnp",
            imports=[
                "/opt/sandstorm/latest/usr/include",
            ]
        )


# Assuming capnp schema files are located as per the example, importing Sandstorm's capnp files
import sandstorm_http_bridge_capnp
import hack_session_capnp


That being said, I am obviously doing something wrong because I am always getting stuck with messages in the console that essentially say that hack sessiion and http brindge are failing to load.

It's as if I'm missing a step somewhere to compile python modules out of the capnp files (ps: ive tried that too, and failed miserably).

PS I am using vagrant-spk with a custom stack that is included in the repo and is desitined to be temporarily placed in the vagrant stack directory I guess. It's the python stack with Sqlite instead of mysql and hence all the mysql stuff removed.

Here is the repo:

https://app.hrbr.life/shared/ytWaJWurdWB8gJrks4e7nTdtRp5Ua_AcvikcZyD9daB


Troy Farrell

unread,
Apr 10, 2024, 12:13:19 PMApr 10
to Sandstorm Development
I cloned the project, spun up a VM with vagrant-spk and here's what I get:

** SANDSTORM SUPERVISOR: Starting up grain. 
Sandbox type: userns 
Traceback (most recent call last):
File "/opt/app/app.py", line 65, in <module> import sandstorm_http_bridge_capnp
ModuleNotFoundError: No module named 'sandstorm_http_bridge_capnp'
** HTTP-BRIDGE: App server exited with status code: 1
** SANDSTORM SUPERVISOR: App exited with status code: 1

So, yes, failing to load sandstorm_http_bridge_capnp.  I suspect we can fix that if the capnp library is working.  Indeed, line 16 of app.py is already importing the sandstorm_http_bridge_capnp module, but under the variable bridge, so we can simply replace bridge = with sandstorm_http_bridge_capnp = on line 16 and comment out the import instruction on line 67.  The hack_session_capnp module is not used anywhere, so we can comment out the import instruction on line 68.  After doing this, I get this error:

sqlite3.OperationalError: unable to open database file

Line 75 of app.py looks like this:

database_path = os.path.join(os.getcwd(), 'vagranttest.db')

The current directory of an app that is starting in a grain is the filesystem root '/', so database_path here is '/vagranttest.db', which is not where line 27 of .sandstorm/launcher.sh creates it.  I would suggest changing app.py to point to '/var/db/...' because any path that needs to be writable inside a grain must start with '/var/'.  Line 33 of .sandstorm/launcher.sh also seems suspect.  It looks for a database inside the '/opt/app/var/db' directory, which does not exist in git.  (Maybe it exists on your laptop.)  If we change it to '/var/db/...' then it will never run because of the touch command on line 29.

After I fixed it so the database error went away, uwsgi gives me a 500 Internal Server Error because main.py is not in the git repository.

I think that I can leave it for you to clean up some of these errors.  You may be able to make email_service.py work if you replace import sandstorm_http_bridge_capnp with the now-working line 16 from app.py.

Good luck!
Troy
Reply all
Reply to author
Forward
0 new messages