diff --git a/README.md b/README.md
index d555a6672..fa3ee643b 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,72 @@ $ echo "Hello, {{.Env.USER}}" | gomplate
 Hello, hairyhenderson
 ```
 
+#### About `.Env`
+
+You can easily access environment variables with `.Env`, but there's a catch:
+if you try to reference an environment variable that doesn't exist, parsing
+will fail and `gomplate` will exit with an error condition.
+
+Sometimes, this behaviour is desired; if the output is unusable without certain strings, this is a sure way to know that variables are missing!
+
+If you want different behaviour, try `getenv` (below).
+
+### Built-in functions
+
+In addition to all of the functions and operators that the [Go template](https://golang.org/pkg/text/template/)
+language provides (`if`, `else`, `eq`, `and`, `or`, `range`, etc...), there are
+some additional functions baked in to `gomplate`:
+
+#### `getenv`
+
+Exposes the [os.Getenv](https://golang.org/pkg/os/#Getenv) function.
+
+This is a more forgiving alternative to using `.Env`, since missing keys will
+return an empty string.
+
+##### Example
+
+```console
+$ echo 'Hello, {{getenv "USER"}}' | gomplate
+Hello, hairyhenderson
+```
+#### `bool`
+
+Converts a true-ish string to a boolean. Can be used to simplify conditional statements based on environment variables or other text input.
+
+##### Example
+
+_`input.tmpl`:_
+```
+{{if bool (getenv "FOO")}}foo{{else}}bar{{end}}
+```
+
+```console
+$ gomplate < input.tmpl
+bar
+$ FOO=true gomplate < input.tmpl
+foo
+```
+
+### Some more complex examples
+
+##### Variable assignment and `if`/`else`
+
+_`input.tmpl`:_
+```
+{{ $u := getenv "USER" }}
+{{ if eq $u "root" }}You are root!{{else}}You are not root :({{end}}
+```
+
+```console
+$ gomplate < input.tmpl
+You are not root :(
+$ sudo gomplate < input.tmpl
+You are root!
+```
+
+_Note:_ it's important for the `if`/`else`/`end` keywords to appear on the same line, or else `gomplate` will not be able to parse the pipeline properly
+
 ## License
 
 [The MIT License](http://opensource.org/licenses/MIT)
diff --git a/main.go b/main.go
index a6537b321..c5ed4f8ae 100644
--- a/main.go
+++ b/main.go
@@ -1,12 +1,13 @@
 package main
 
 import (
-	"bufio"
 	"flag"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"log"
 	"os"
+	"strconv"
 
 	"text/template"
 )
@@ -23,25 +24,49 @@ func init() {
 	}
 }
 
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+	return os.Getenv(key)
+}
+
+// Bool converts a string to a boolean value, using strconv.ParseBool under the covers.
+// Possible true values are: 1, t, T, TRUE, true, True
+// All other values are considered false.
+func Bool(in string) bool {
+	if b, err := strconv.ParseBool(in); err == nil {
+		return b
+	}
+	return false
+}
+
+var funcMap = template.FuncMap{
+	"Getenv": Getenv,
+	"getenv": Getenv,
+	"Bool":   Bool,
+	"bool":   Bool,
+}
+
 func createTemplate() *template.Template {
-	return template.New("template").Option("missingkey=error")
+	return template.New("template").Funcs(funcMap).Option("missingkey=error")
 }
 
 // RunTemplate -
 func RunTemplate(in io.Reader, out io.Writer) {
-	s := bufio.NewScanner(in)
 	context := &Context{}
-	for s.Scan() {
-		tmpl, err := createTemplate().Parse(s.Text())
-		if err != nil {
-			log.Fatalf("Line %q: %v\n", s.Text(), err)
-		}
-
-		if err := tmpl.Execute(out, context); err != nil {
-			panic(err)
-		}
-		out.Write([]byte("\n"))
+	text, err := ioutil.ReadAll(in)
+	if err != nil {
+		log.Fatalf("Read failed!\n%v\n", err)
+	}
+	tmpl, err := createTemplate().Parse(string(text))
+	if err != nil {
+		log.Fatalf("Line %q: %v\n", string(text), err)
+	}
+
+	if err := tmpl.Execute(out, context); err != nil {
+		panic(err)
 	}
+	out.Write([]byte("\n"))
 }
 
 func main() {
diff --git a/main_test.go b/main_test.go
new file mode 100644
index 000000000..36a1460b5
--- /dev/null
+++ b/main_test.go
@@ -0,0 +1,40 @@
+package main
+
+import (
+	"bytes"
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func testTemplate(template string) string {
+	in := strings.NewReader(template)
+	var out bytes.Buffer
+	RunTemplate(in, &out)
+	return strings.TrimSpace(out.String())
+}
+
+func TestGetenv(t *testing.T) {
+	assert.Empty(t, Getenv("FOOBARBAZ"))
+	assert.Empty(t, testTemplate(`{{getenv "BLAHBLAHBLAH"}}`))
+	assert.Equal(t, Getenv("USER"), os.Getenv("USER"))
+	assert.Equal(t, os.Getenv("USER"), testTemplate(`{{getenv "USER"}}`))
+}
+
+func TestBool(t *testing.T) {
+	assert.False(t, Bool(""))
+	assert.False(t, Bool("asdf"))
+	assert.False(t, Bool("1234"))
+	assert.False(t, Bool("False"))
+	assert.False(t, Bool("0"))
+	assert.False(t, Bool("false"))
+	assert.False(t, Bool("F"))
+	assert.False(t, Bool("f"))
+	assert.True(t, Bool("true"))
+	assert.True(t, Bool("True"))
+	assert.True(t, Bool("t"))
+	assert.True(t, Bool("T"))
+	assert.True(t, Bool("1"))
+}